svc_synchronization.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/scope_exit.h"
  4. #include "core/core.h"
  5. #include "core/hle/kernel/k_process.h"
  6. #include "core/hle/kernel/k_readable_event.h"
  7. #include "core/hle/kernel/svc.h"
  8. namespace Kernel::Svc {
  9. /// Close a handle
  10. Result CloseHandle(Core::System& system, Handle handle) {
  11. LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
  12. // Remove the handle.
  13. R_UNLESS(GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(handle),
  14. ResultInvalidHandle);
  15. R_SUCCEED();
  16. }
  17. /// Clears the signaled state of an event or process.
  18. Result ResetSignal(Core::System& system, Handle handle) {
  19. LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
  20. // Get the current handle table.
  21. const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
  22. // Try to reset as readable event.
  23. {
  24. KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
  25. if (readable_event.IsNotNull()) {
  26. R_RETURN(readable_event->Reset());
  27. }
  28. }
  29. // Try to reset as process.
  30. {
  31. KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
  32. if (process.IsNotNull()) {
  33. R_RETURN(process->Reset());
  34. }
  35. }
  36. R_THROW(ResultInvalidHandle);
  37. }
  38. static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles,
  39. int32_t num_handles, int64_t timeout_ns) {
  40. // Ensure number of handles is valid.
  41. R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
  42. // Get the synchronization context.
  43. auto& kernel = system.Kernel();
  44. auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
  45. std::vector<KSynchronizationObject*> objs(num_handles);
  46. // Copy user handles.
  47. if (num_handles > 0) {
  48. // Convert the handles to objects.
  49. R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
  50. num_handles),
  51. ResultInvalidHandle);
  52. }
  53. // Ensure handles are closed when we're done.
  54. SCOPE_EXIT({
  55. for (auto i = 0; i < num_handles; ++i) {
  56. objs[i]->Close();
  57. }
  58. });
  59. // Wait on the objects.
  60. Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(),
  61. static_cast<s32>(objs.size()), timeout_ns);
  62. R_SUCCEED_IF(res == ResultSessionClosed);
  63. R_RETURN(res);
  64. }
  65. /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
  66. Result WaitSynchronization(Core::System& system, int32_t* out_index, VAddr user_handles,
  67. int32_t num_handles, int64_t timeout_ns) {
  68. LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
  69. num_handles, timeout_ns);
  70. // Ensure number of handles is valid.
  71. R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
  72. std::vector<Handle> handles(num_handles);
  73. if (num_handles > 0) {
  74. system.Memory().ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle));
  75. }
  76. R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns));
  77. }
  78. /// Resumes a thread waiting on WaitSynchronization
  79. Result CancelSynchronization(Core::System& system, Handle handle) {
  80. LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
  81. // Get the thread from its handle.
  82. KScopedAutoObject thread =
  83. GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle);
  84. R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
  85. // Cancel the thread's wait.
  86. thread->WaitCancel();
  87. R_SUCCEED();
  88. }
  89. void SynchronizePreemptionState(Core::System& system) {
  90. auto& kernel = system.Kernel();
  91. // Lock the scheduler.
  92. KScopedSchedulerLock sl{kernel};
  93. // If the current thread is pinned, unpin it.
  94. KProcess* cur_process = GetCurrentProcessPointer(kernel);
  95. const auto core_id = GetCurrentCoreId(kernel);
  96. if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
  97. // Clear the current thread's interrupt flag.
  98. GetCurrentThread(kernel).ClearInterruptFlag();
  99. // Unpin the current thread.
  100. cur_process->UnpinCurrentThread(core_id);
  101. }
  102. }
  103. Result CloseHandle64(Core::System& system, Handle handle) {
  104. R_RETURN(CloseHandle(system, handle));
  105. }
  106. Result ResetSignal64(Core::System& system, Handle handle) {
  107. R_RETURN(ResetSignal(system, handle));
  108. }
  109. Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles,
  110. int32_t num_handles, int64_t timeout_ns) {
  111. R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
  112. }
  113. Result CancelSynchronization64(Core::System& system, Handle handle) {
  114. R_RETURN(CancelSynchronization(system, handle));
  115. }
  116. void SynchronizePreemptionState64(Core::System& system) {
  117. SynchronizePreemptionState(system);
  118. }
  119. Result CloseHandle64From32(Core::System& system, Handle handle) {
  120. R_RETURN(CloseHandle(system, handle));
  121. }
  122. Result ResetSignal64From32(Core::System& system, Handle handle) {
  123. R_RETURN(ResetSignal(system, handle));
  124. }
  125. Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles,
  126. int32_t num_handles, int64_t timeout_ns) {
  127. R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
  128. }
  129. Result CancelSynchronization64From32(Core::System& system, Handle handle) {
  130. R_RETURN(CancelSynchronization(system, handle));
  131. }
  132. void SynchronizePreemptionState64From32(Core::System& system) {
  133. SynchronizePreemptionState(system);
  134. }
  135. } // namespace Kernel::Svc