svc_synchronization.cpp 5.6 KB

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