svc_synchronization.cpp 5.9 KB

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