diff options
Diffstat (limited to 'src')
33 files changed, 397 insertions, 621 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d0c1beaf7..548b3911e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -164,6 +164,8 @@ add_library(core STATIC | |||
| 164 | hle/kernel/k_scheduler_lock.h | 164 | hle/kernel/k_scheduler_lock.h |
| 165 | hle/kernel/k_scoped_lock.h | 165 | hle/kernel/k_scoped_lock.h |
| 166 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 166 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h |
| 167 | hle/kernel/k_synchronization_object.cpp | ||
| 168 | hle/kernel/k_synchronization_object.h | ||
| 167 | hle/kernel/kernel.cpp | 169 | hle/kernel/kernel.cpp |
| 168 | hle/kernel/kernel.h | 170 | hle/kernel/kernel.h |
| 169 | hle/kernel/memory/address_space_info.cpp | 171 | hle/kernel/memory/address_space_info.cpp |
| @@ -213,10 +215,6 @@ add_library(core STATIC | |||
| 213 | hle/kernel/svc_results.h | 215 | hle/kernel/svc_results.h |
| 214 | hle/kernel/svc_types.h | 216 | hle/kernel/svc_types.h |
| 215 | hle/kernel/svc_wrap.h | 217 | hle/kernel/svc_wrap.h |
| 216 | hle/kernel/synchronization_object.cpp | ||
| 217 | hle/kernel/synchronization_object.h | ||
| 218 | hle/kernel/synchronization.cpp | ||
| 219 | hle/kernel/synchronization.h | ||
| 220 | hle/kernel/thread.cpp | 218 | hle/kernel/thread.cpp |
| 221 | hle/kernel/thread.h | 219 | hle/kernel/thread.h |
| 222 | hle/kernel/time_manager.cpp | 220 | hle/kernel/time_manager.cpp |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 20ffa7d47..23e1ef032 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -37,7 +37,7 @@ void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& wai | |||
| 37 | waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); | 37 | waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); |
| 38 | RemoveThread(waiting_threads[i]); | 38 | RemoveThread(waiting_threads[i]); |
| 39 | waiting_threads[i]->WaitForArbitration(false); | 39 | waiting_threads[i]->WaitForArbitration(false); |
| 40 | waiting_threads[i]->ResumeFromWait(); | 40 | waiting_threads[i]->Wakeup(); |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| 43 | 43 | ||
| @@ -160,7 +160,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 | |||
| 160 | { | 160 | { |
| 161 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); | 161 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); |
| 162 | 162 | ||
| 163 | if (current_thread->IsPendingTermination()) { | 163 | if (current_thread->IsTerminationRequested()) { |
| 164 | lock.CancelSleep(); | 164 | lock.CancelSleep(); |
| 165 | return ERR_THREAD_TERMINATING; | 165 | return ERR_THREAD_TERMINATING; |
| 166 | } | 166 | } |
| @@ -201,7 +201,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 | |||
| 201 | 201 | ||
| 202 | current_thread->SetArbiterWaitAddress(address); | 202 | current_thread->SetArbiterWaitAddress(address); |
| 203 | InsertThread(SharedFrom(current_thread)); | 203 | InsertThread(SharedFrom(current_thread)); |
| 204 | current_thread->SetStatus(ThreadStatus::WaitArb); | 204 | current_thread->SetState(ThreadStatus::WaitArb); |
| 205 | current_thread->WaitForArbitration(true); | 205 | current_thread->WaitForArbitration(true); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| @@ -230,7 +230,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t | |||
| 230 | { | 230 | { |
| 231 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); | 231 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); |
| 232 | 232 | ||
| 233 | if (current_thread->IsPendingTermination()) { | 233 | if (current_thread->IsTerminationRequested()) { |
| 234 | lock.CancelSleep(); | 234 | lock.CancelSleep(); |
| 235 | return ERR_THREAD_TERMINATING; | 235 | return ERR_THREAD_TERMINATING; |
| 236 | } | 236 | } |
| @@ -256,7 +256,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t | |||
| 256 | current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); | 256 | current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); |
| 257 | current_thread->SetArbiterWaitAddress(address); | 257 | current_thread->SetArbiterWaitAddress(address); |
| 258 | InsertThread(SharedFrom(current_thread)); | 258 | InsertThread(SharedFrom(current_thread)); |
| 259 | current_thread->SetStatus(ThreadStatus::WaitArb); | 259 | current_thread->SetState(ThreadStatus::WaitArb); |
| 260 | current_thread->WaitForArbitration(true); | 260 | current_thread->WaitForArbitration(true); |
| 261 | } | 261 | } |
| 262 | 262 | ||
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 8aff2227a..f8f005f15 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp | |||
| @@ -33,9 +33,6 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { | |||
| 33 | server_port->AppendPendingSession(std::move(server)); | 33 | server_port->AppendPendingSession(std::move(server)); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | // Wake the threads waiting on the ServerPort | ||
| 37 | server_port->Signal(); | ||
| 38 | |||
| 39 | return MakeResult(std::move(client)); | 36 | return MakeResult(std::move(client)); |
| 40 | } | 37 | } |
| 41 | 38 | ||
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index be9eba519..e8e52900d 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| 15 | ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {} | 15 | ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 16 | 16 | ||
| 17 | ClientSession::~ClientSession() { | 17 | ClientSession::~ClientSession() { |
| 18 | // This destructor will be called automatically when the last ClientSession handle is closed by | 18 | // This destructor will be called automatically when the last ClientSession handle is closed by |
| @@ -22,15 +22,6 @@ ClientSession::~ClientSession() { | |||
| 22 | } | 22 | } |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | bool ClientSession::ShouldWait(const Thread* thread) const { | ||
| 26 | UNIMPLEMENTED(); | ||
| 27 | return {}; | ||
| 28 | } | ||
| 29 | |||
| 30 | void ClientSession::Acquire(Thread* thread) { | ||
| 31 | UNIMPLEMENTED(); | ||
| 32 | } | ||
| 33 | |||
| 34 | bool ClientSession::IsSignaled() const { | 25 | bool ClientSession::IsSignaled() const { |
| 35 | UNIMPLEMENTED(); | 26 | UNIMPLEMENTED(); |
| 36 | return true; | 27 | return true; |
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index e5e0690c2..d5c9ebee8 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | 9 | ||
| 10 | #include "core/hle/kernel/synchronization_object.h" | 10 | #include "core/hle/kernel/k_synchronization_object.h" |
| 11 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| 12 | 12 | ||
| 13 | union ResultCode; | 13 | union ResultCode; |
| @@ -26,7 +26,7 @@ class KernelCore; | |||
| 26 | class Session; | 26 | class Session; |
| 27 | class Thread; | 27 | class Thread; |
| 28 | 28 | ||
| 29 | class ClientSession final : public SynchronizationObject { | 29 | class ClientSession final : public KSynchronizationObject { |
| 30 | public: | 30 | public: |
| 31 | explicit ClientSession(KernelCore& kernel); | 31 | explicit ClientSession(KernelCore& kernel); |
| 32 | ~ClientSession() override; | 32 | ~ClientSession() override; |
| @@ -49,10 +49,6 @@ public: | |||
| 49 | ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, | 49 | ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, |
| 50 | Core::Timing::CoreTiming& core_timing); | 50 | Core::Timing::CoreTiming& core_timing); |
| 51 | 51 | ||
| 52 | bool ShouldWait(const Thread* thread) const override; | ||
| 53 | |||
| 54 | void Acquire(Thread* thread) override; | ||
| 55 | |||
| 56 | bool IsSignaled() const override; | 52 | bool IsSignaled() const override; |
| 57 | 53 | ||
| 58 | private: | 54 | private: |
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index d4e5d88cf..7d32a39f0 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h | |||
| @@ -13,12 +13,14 @@ namespace Kernel { | |||
| 13 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; | 13 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; |
| 14 | constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; | 14 | constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; |
| 15 | constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59}; | 15 | constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59}; |
| 16 | constexpr ResultCode ERR_TERMINATION_REQUESTED{ErrorModule::Kernel, 59}; | ||
| 16 | constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; | 17 | constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; |
| 17 | constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; | 18 | constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; |
| 18 | constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103}; | 19 | constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103}; |
| 19 | constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104}; | 20 | constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104}; |
| 20 | constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; | 21 | constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; |
| 21 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106}; | 22 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106}; |
| 23 | constexpr ResultCode ERR_INVALID_CURRENT_MEMORY{ErrorModule::Kernel, 106}; | ||
| 22 | constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; | 24 | constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; |
| 23 | constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110}; | 25 | constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110}; |
| 24 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113}; | 26 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113}; |
| @@ -28,6 +30,7 @@ constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115}; | |||
| 28 | constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116}; | 30 | constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116}; |
| 29 | constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117}; | 31 | constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117}; |
| 30 | constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118}; | 32 | constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118}; |
| 33 | constexpr ResultCode ERR_CANCELLED{ErrorModule::Kernel, 118}; | ||
| 31 | constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119}; | 34 | constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119}; |
| 32 | constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120}; | 35 | constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120}; |
| 33 | constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121}; | 36 | constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121}; |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index c5fd82a6b..f44d31992 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -645,8 +645,7 @@ void KScheduler::Unload(Thread* thread) { | |||
| 645 | 645 | ||
| 646 | void KScheduler::Reload(Thread* thread) { | 646 | void KScheduler::Reload(Thread* thread) { |
| 647 | if (thread) { | 647 | if (thread) { |
| 648 | ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, | 648 | ASSERT_MSG(thread->GetState() == ThreadSchedStatus::Runnable, "Thread must be runnable."); |
| 649 | "Thread must be runnable."); | ||
| 650 | 649 | ||
| 651 | // Cancel any outstanding wakeup events for this thread | 650 | // Cancel any outstanding wakeup events for this thread |
| 652 | thread->SetIsRunning(true); | 651 | thread->SetIsRunning(true); |
| @@ -772,7 +771,7 @@ void KScheduler::Initialize() { | |||
| 772 | 771 | ||
| 773 | { | 772 | { |
| 774 | KScopedSchedulerLock lock{system.Kernel()}; | 773 | KScopedSchedulerLock lock{system.Kernel()}; |
| 775 | idle_thread->SetStatus(ThreadStatus::Ready); | 774 | idle_thread->SetState(ThreadStatus::Ready); |
| 776 | } | 775 | } |
| 777 | } | 776 | } |
| 778 | 777 | ||
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp new file mode 100644 index 000000000..e7fd119d8 --- /dev/null +++ b/src/core/hle/kernel/k_synchronization_object.cpp | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 9 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/svc_results.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, | ||
| 17 | KSynchronizationObject** objects, const s32 num_objects, | ||
| 18 | s64 timeout) { | ||
| 19 | // Allocate space on stack for thread nodes. | ||
| 20 | std::vector<ThreadListNode> thread_nodes(num_objects); | ||
| 21 | |||
| 22 | // Prepare for wait. | ||
| 23 | Thread* thread = kernel.CurrentScheduler()->GetCurrentThread(); | ||
| 24 | Handle timer = InvalidHandle; | ||
| 25 | |||
| 26 | { | ||
| 27 | // Setup the scheduling lock and sleep. | ||
| 28 | KScopedSchedulerLockAndSleep slp(kernel, timer, thread, timeout); | ||
| 29 | |||
| 30 | // Check if any of the objects are already signaled. | ||
| 31 | for (auto i = 0; i < num_objects; ++i) { | ||
| 32 | ASSERT(objects[i] != nullptr); | ||
| 33 | |||
| 34 | if (objects[i]->IsSignaled()) { | ||
| 35 | *out_index = i; | ||
| 36 | slp.CancelSleep(); | ||
| 37 | return RESULT_SUCCESS; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | // Check if the timeout is zero. | ||
| 42 | if (timeout == 0) { | ||
| 43 | slp.CancelSleep(); | ||
| 44 | return Svc::ResultTimedOut; | ||
| 45 | } | ||
| 46 | |||
| 47 | // Check if the thread should terminate. | ||
| 48 | if (thread->IsTerminationRequested()) { | ||
| 49 | slp.CancelSleep(); | ||
| 50 | return Svc::ResultTerminationRequested; | ||
| 51 | } | ||
| 52 | |||
| 53 | // Check if waiting was canceled. | ||
| 54 | if (thread->IsWaitCancelled()) { | ||
| 55 | slp.CancelSleep(); | ||
| 56 | thread->ClearWaitCancelled(); | ||
| 57 | return Svc::ResultCancelled; | ||
| 58 | } | ||
| 59 | |||
| 60 | // Add the waiters. | ||
| 61 | for (auto i = 0; i < num_objects; ++i) { | ||
| 62 | thread_nodes[i].thread = thread; | ||
| 63 | thread_nodes[i].next = nullptr; | ||
| 64 | |||
| 65 | if (objects[i]->thread_list_tail == nullptr) { | ||
| 66 | objects[i]->thread_list_head = std::addressof(thread_nodes[i]); | ||
| 67 | } else { | ||
| 68 | objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); | ||
| 69 | } | ||
| 70 | |||
| 71 | objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); | ||
| 72 | } | ||
| 73 | |||
| 74 | // For debugging only | ||
| 75 | thread->SetWaitObjectsForDebugging(objects, num_objects); | ||
| 76 | |||
| 77 | // Mark the thread as waiting. | ||
| 78 | thread->SetCancellable(); | ||
| 79 | thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); | ||
| 80 | thread->SetState(ThreadState::WaitSynch); | ||
| 81 | } | ||
| 82 | |||
| 83 | // The lock/sleep is done, so we should be able to get our result. | ||
| 84 | |||
| 85 | // Thread is no longer cancellable. | ||
| 86 | thread->ClearCancellable(); | ||
| 87 | |||
| 88 | // For debugging only | ||
| 89 | thread->SetWaitObjectsForDebugging(nullptr, 0); | ||
| 90 | |||
| 91 | // Cancel the timer as needed. | ||
| 92 | if (timer != InvalidHandle) { | ||
| 93 | auto& time_manager = kernel.TimeManager(); | ||
| 94 | time_manager.UnscheduleTimeEvent(timer); | ||
| 95 | } | ||
| 96 | |||
| 97 | // Get the wait result. | ||
| 98 | ResultCode wait_result{RESULT_SUCCESS}; | ||
| 99 | s32 sync_index = -1; | ||
| 100 | { | ||
| 101 | KScopedSchedulerLock lock(kernel); | ||
| 102 | KSynchronizationObject* synced_obj; | ||
| 103 | wait_result = thread->GetWaitResult(std::addressof(synced_obj)); | ||
| 104 | |||
| 105 | for (auto i = 0; i < num_objects; ++i) { | ||
| 106 | // Unlink the object from the list. | ||
| 107 | ThreadListNode* prev_ptr = | ||
| 108 | reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head)); | ||
| 109 | ThreadListNode* prev_val = nullptr; | ||
| 110 | ThreadListNode *prev, *tail_prev; | ||
| 111 | |||
| 112 | do { | ||
| 113 | prev = prev_ptr; | ||
| 114 | prev_ptr = prev_ptr->next; | ||
| 115 | tail_prev = prev_val; | ||
| 116 | prev_val = prev_ptr; | ||
| 117 | } while (prev_ptr != std::addressof(thread_nodes[i])); | ||
| 118 | |||
| 119 | if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { | ||
| 120 | objects[i]->thread_list_tail = tail_prev; | ||
| 121 | } | ||
| 122 | |||
| 123 | prev->next = thread_nodes[i].next; | ||
| 124 | |||
| 125 | if (objects[i] == synced_obj) { | ||
| 126 | sync_index = i; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | // Set output. | ||
| 132 | *out_index = sync_index; | ||
| 133 | return wait_result; | ||
| 134 | } | ||
| 135 | |||
| 136 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} | ||
| 137 | |||
| 138 | KSynchronizationObject ::~KSynchronizationObject() = default; | ||
| 139 | |||
| 140 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { | ||
| 141 | KScopedSchedulerLock lock(kernel); | ||
| 142 | |||
| 143 | // If we're not signaled, we've nothing to notify. | ||
| 144 | if (!this->IsSignaled()) { | ||
| 145 | return; | ||
| 146 | } | ||
| 147 | |||
| 148 | // Iterate over each thread. | ||
| 149 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { | ||
| 150 | Thread* thread = cur_node->thread; | ||
| 151 | if (thread->GetState() == ThreadSchedStatus::Paused) { | ||
| 152 | thread->SetSyncedObject(this, result); | ||
| 153 | thread->SetState(ThreadStatus::Ready); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const { | ||
| 159 | std::vector<Thread*> threads; | ||
| 160 | |||
| 161 | // If debugging, dump the list of waiters. | ||
| 162 | { | ||
| 163 | KScopedSchedulerLock lock(kernel); | ||
| 164 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { | ||
| 165 | threads.emplace_back(cur_node->thread); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | return threads; | ||
| 170 | } | ||
| 171 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h new file mode 100644 index 000000000..14d80ebf1 --- /dev/null +++ b/src/core/hle/kernel/k_synchronization_object.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "core/hle/kernel/object.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | class KernelCore; | ||
| 15 | class Synchronization; | ||
| 16 | class Thread; | ||
| 17 | |||
| 18 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 19 | class KSynchronizationObject : public Object { | ||
| 20 | public: | ||
| 21 | struct ThreadListNode { | ||
| 22 | ThreadListNode* next{}; | ||
| 23 | Thread* thread{}; | ||
| 24 | }; | ||
| 25 | |||
| 26 | [[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index, | ||
| 27 | KSynchronizationObject** objects, const s32 num_objects, | ||
| 28 | s64 timeout); | ||
| 29 | |||
| 30 | [[nodiscard]] virtual bool IsSignaled() const = 0; | ||
| 31 | |||
| 32 | [[nodiscard]] std::vector<Thread*> GetWaitingThreadsForDebugging() const; | ||
| 33 | |||
| 34 | protected: | ||
| 35 | explicit KSynchronizationObject(KernelCore& kernel); | ||
| 36 | virtual ~KSynchronizationObject(); | ||
| 37 | |||
| 38 | void NotifyAvailable(ResultCode result); | ||
| 39 | void NotifyAvailable() { | ||
| 40 | return this->NotifyAvailable(RESULT_SUCCESS); | ||
| 41 | } | ||
| 42 | |||
| 43 | private: | ||
| 44 | ThreadListNode* thread_list_head{}; | ||
| 45 | ThreadListNode* thread_list_tail{}; | ||
| 46 | }; | ||
| 47 | |||
| 48 | // Specialization of DynamicObjectCast for KSynchronizationObjects | ||
| 49 | template <> | ||
| 50 | inline std::shared_ptr<KSynchronizationObject> DynamicObjectCast<KSynchronizationObject>( | ||
| 51 | std::shared_ptr<Object> object) { | ||
| 52 | if (object != nullptr && object->IsWaitable()) { | ||
| 53 | return std::static_pointer_cast<KSynchronizationObject>(object); | ||
| 54 | } | ||
| 55 | return nullptr; | ||
| 56 | } | ||
| 57 | |||
| 58 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e8ece8164..f1dcbe2eb 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | #include "core/hle/kernel/resource_limit.h" | 38 | #include "core/hle/kernel/resource_limit.h" |
| 39 | #include "core/hle/kernel/service_thread.h" | 39 | #include "core/hle/kernel/service_thread.h" |
| 40 | #include "core/hle/kernel/shared_memory.h" | 40 | #include "core/hle/kernel/shared_memory.h" |
| 41 | #include "core/hle/kernel/synchronization.h" | ||
| 42 | #include "core/hle/kernel/thread.h" | 41 | #include "core/hle/kernel/thread.h" |
| 43 | #include "core/hle/kernel/time_manager.h" | 42 | #include "core/hle/kernel/time_manager.h" |
| 44 | #include "core/hle/lock.h" | 43 | #include "core/hle/lock.h" |
| @@ -51,8 +50,7 @@ namespace Kernel { | |||
| 51 | 50 | ||
| 52 | struct KernelCore::Impl { | 51 | struct KernelCore::Impl { |
| 53 | explicit Impl(Core::System& system, KernelCore& kernel) | 52 | explicit Impl(Core::System& system, KernelCore& kernel) |
| 54 | : synchronization{system}, time_manager{system}, global_handle_table{kernel}, system{ | 53 | : time_manager{system}, global_handle_table{kernel}, system{system} {} |
| 55 | system} {} | ||
| 56 | 54 | ||
| 57 | void SetMulticore(bool is_multicore) { | 55 | void SetMulticore(bool is_multicore) { |
| 58 | this->is_multicore = is_multicore; | 56 | this->is_multicore = is_multicore; |
| @@ -307,7 +305,6 @@ struct KernelCore::Impl { | |||
| 307 | std::vector<std::shared_ptr<Process>> process_list; | 305 | std::vector<std::shared_ptr<Process>> process_list; |
| 308 | Process* current_process = nullptr; | 306 | Process* current_process = nullptr; |
| 309 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 307 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| 310 | Kernel::Synchronization synchronization; | ||
| 311 | Kernel::TimeManager time_manager; | 308 | Kernel::TimeManager time_manager; |
| 312 | 309 | ||
| 313 | std::shared_ptr<ResourceLimit> system_resource_limit; | 310 | std::shared_ptr<ResourceLimit> system_resource_limit; |
| @@ -461,14 +458,6 @@ const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Kern | |||
| 461 | return impl->interrupts; | 458 | return impl->interrupts; |
| 462 | } | 459 | } |
| 463 | 460 | ||
| 464 | Kernel::Synchronization& KernelCore::Synchronization() { | ||
| 465 | return impl->synchronization; | ||
| 466 | } | ||
| 467 | |||
| 468 | const Kernel::Synchronization& KernelCore::Synchronization() const { | ||
| 469 | return impl->synchronization; | ||
| 470 | } | ||
| 471 | |||
| 472 | Kernel::TimeManager& KernelCore::TimeManager() { | 461 | Kernel::TimeManager& KernelCore::TimeManager() { |
| 473 | return impl->time_manager; | 462 | return impl->time_manager; |
| 474 | } | 463 | } |
| @@ -615,7 +604,7 @@ void KernelCore::Suspend(bool in_suspention) { | |||
| 615 | KScopedSchedulerLock lock(*this); | 604 | KScopedSchedulerLock lock(*this); |
| 616 | ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; | 605 | ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; |
| 617 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 606 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 618 | impl->suspend_threads[i]->SetStatus(status); | 607 | impl->suspend_threads[i]->SetState(status); |
| 619 | } | 608 | } |
| 620 | } | 609 | } |
| 621 | } | 610 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index e3169f5a7..9046b5a8a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -129,12 +129,6 @@ public: | |||
| 129 | /// Gets the an instance of the current physical CPU core. | 129 | /// Gets the an instance of the current physical CPU core. |
| 130 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; | 130 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; |
| 131 | 131 | ||
| 132 | /// Gets the an instance of the Synchronization Interface. | ||
| 133 | Kernel::Synchronization& Synchronization(); | ||
| 134 | |||
| 135 | /// Gets the an instance of the Synchronization Interface. | ||
| 136 | const Kernel::Synchronization& Synchronization() const; | ||
| 137 | |||
| 138 | /// Gets the an instance of the TimeManager Interface. | 132 | /// Gets the an instance of the TimeManager Interface. |
| 139 | Kernel::TimeManager& TimeManager(); | 133 | Kernel::TimeManager& TimeManager(); |
| 140 | 134 | ||
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 4f8075e0e..badd883aa 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -107,7 +107,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 107 | current_thread->SetMutexWaitAddress(address); | 107 | current_thread->SetMutexWaitAddress(address); |
| 108 | current_thread->SetWaitHandle(requesting_thread_handle); | 108 | current_thread->SetWaitHandle(requesting_thread_handle); |
| 109 | 109 | ||
| 110 | current_thread->SetStatus(ThreadStatus::WaitMutex); | 110 | current_thread->SetState(ThreadStatus::WaitMutex); |
| 111 | 111 | ||
| 112 | // Update the lock holder thread's priority to prevent priority inversion. | 112 | // Update the lock holder thread's priority to prevent priority inversion. |
| 113 | holding_thread->AddMutexWaiter(current_thread); | 113 | holding_thread->AddMutexWaiter(current_thread); |
| @@ -145,7 +145,7 @@ std::pair<ResultCode, std::shared_ptr<Thread>> Mutex::Unlock(std::shared_ptr<Thr | |||
| 145 | } | 145 | } |
| 146 | new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS); | 146 | new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS); |
| 147 | new_owner->SetLockOwner(nullptr); | 147 | new_owner->SetLockOwner(nullptr); |
| 148 | new_owner->ResumeFromWait(); | 148 | new_owner->Wakeup(); |
| 149 | 149 | ||
| 150 | system.Memory().Write32(address, mutex_value); | 150 | system.Memory().Write32(address, mutex_value); |
| 151 | return {RESULT_SUCCESS, new_owner}; | 151 | return {RESULT_SUCCESS, new_owner}; |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b905b486a..92e877c3e 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -55,7 +55,7 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, | |||
| 55 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires | 55 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires |
| 56 | { | 56 | { |
| 57 | KScopedSchedulerLock lock{kernel}; | 57 | KScopedSchedulerLock lock{kernel}; |
| 58 | thread->SetStatus(ThreadStatus::Ready); | 58 | thread->SetState(ThreadStatus::Ready); |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | } // Anonymous namespace | 61 | } // Anonymous namespace |
| @@ -406,21 +406,18 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) { | |||
| 406 | ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite); | 406 | ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite); |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | bool Process::IsSignaled() const { | ||
| 410 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 411 | return is_signaled; | ||
| 412 | } | ||
| 413 | |||
| 409 | Process::Process(Core::System& system) | 414 | Process::Process(Core::System& system) |
| 410 | : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>( | 415 | : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>( |
| 411 | system)}, | 416 | system)}, |
| 412 | handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} | 417 | handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} |
| 413 | 418 | ||
| 414 | Process::~Process() = default; | 419 | Process::~Process() = default; |
| 415 | 420 | ||
| 416 | void Process::Acquire(Thread* thread) { | ||
| 417 | ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); | ||
| 418 | } | ||
| 419 | |||
| 420 | bool Process::ShouldWait(const Thread* thread) const { | ||
| 421 | return !is_signaled; | ||
| 422 | } | ||
| 423 | |||
| 424 | void Process::ChangeStatus(ProcessStatus new_status) { | 421 | void Process::ChangeStatus(ProcessStatus new_status) { |
| 425 | if (status == new_status) { | 422 | if (status == new_status) { |
| 426 | return; | 423 | return; |
| @@ -428,7 +425,7 @@ void Process::ChangeStatus(ProcessStatus new_status) { | |||
| 428 | 425 | ||
| 429 | status = new_status; | 426 | status = new_status; |
| 430 | is_signaled = true; | 427 | is_signaled = true; |
| 431 | Signal(); | 428 | NotifyAvailable(); |
| 432 | } | 429 | } |
| 433 | 430 | ||
| 434 | ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { | 431 | ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index e412e58aa..901f1ff27 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -13,9 +13,9 @@ | |||
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "core/hle/kernel/address_arbiter.h" | 14 | #include "core/hle/kernel/address_arbiter.h" |
| 15 | #include "core/hle/kernel/handle_table.h" | 15 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 16 | #include "core/hle/kernel/mutex.h" | 17 | #include "core/hle/kernel/mutex.h" |
| 17 | #include "core/hle/kernel/process_capability.h" | 18 | #include "core/hle/kernel/process_capability.h" |
| 18 | #include "core/hle/kernel/synchronization_object.h" | ||
| 19 | #include "core/hle/result.h" | 19 | #include "core/hle/result.h" |
| 20 | 20 | ||
| 21 | namespace Core { | 21 | namespace Core { |
| @@ -63,7 +63,7 @@ enum class ProcessStatus { | |||
| 63 | DebugBreak, | 63 | DebugBreak, |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | class Process final : public SynchronizationObject { | 66 | class Process final : public KSynchronizationObject { |
| 67 | public: | 67 | public: |
| 68 | explicit Process(Core::System& system); | 68 | explicit Process(Core::System& system); |
| 69 | ~Process() override; | 69 | ~Process() override; |
| @@ -304,6 +304,8 @@ public: | |||
| 304 | 304 | ||
| 305 | void LoadModule(CodeSet code_set, VAddr base_addr); | 305 | void LoadModule(CodeSet code_set, VAddr base_addr); |
| 306 | 306 | ||
| 307 | bool IsSignaled() const override; | ||
| 308 | |||
| 307 | /////////////////////////////////////////////////////////////////////////////////////////////// | 309 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 308 | // Thread-local storage management | 310 | // Thread-local storage management |
| 309 | 311 | ||
| @@ -314,12 +316,6 @@ public: | |||
| 314 | void FreeTLSRegion(VAddr tls_address); | 316 | void FreeTLSRegion(VAddr tls_address); |
| 315 | 317 | ||
| 316 | private: | 318 | private: |
| 317 | /// Checks if the specified thread should wait until this process is available. | ||
| 318 | bool ShouldWait(const Thread* thread) const override; | ||
| 319 | |||
| 320 | /// Acquires/locks this process for the specified thread if it's available. | ||
| 321 | void Acquire(Thread* thread) override; | ||
| 322 | |||
| 323 | /// Changes the process status. If the status is different | 319 | /// Changes the process status. If the status is different |
| 324 | /// from the current process status, then this will trigger | 320 | /// from the current process status, then this will trigger |
| 325 | /// a process signal. | 321 | /// a process signal. |
| @@ -410,6 +406,8 @@ private: | |||
| 410 | /// Schedule count of this process | 406 | /// Schedule count of this process |
| 411 | s64 schedule_count{}; | 407 | s64 schedule_count{}; |
| 412 | 408 | ||
| 409 | bool is_signaled{}; | ||
| 410 | |||
| 413 | /// System context | 411 | /// System context |
| 414 | Core::System& system; | 412 | Core::System& system; |
| 415 | }; | 413 | }; |
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index cea262ce0..99ed0857e 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp | |||
| @@ -14,24 +14,22 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {} | 17 | ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 18 | ReadableEvent::~ReadableEvent() = default; | 18 | ReadableEvent::~ReadableEvent() = default; |
| 19 | 19 | ||
| 20 | bool ReadableEvent::ShouldWait(const Thread* thread) const { | ||
| 21 | return !is_signaled; | ||
| 22 | } | ||
| 23 | |||
| 24 | void ReadableEvent::Acquire(Thread* thread) { | ||
| 25 | ASSERT_MSG(IsSignaled(), "object unavailable!"); | ||
| 26 | } | ||
| 27 | |||
| 28 | void ReadableEvent::Signal() { | 20 | void ReadableEvent::Signal() { |
| 29 | if (is_signaled) { | 21 | if (is_signaled) { |
| 30 | return; | 22 | return; |
| 31 | } | 23 | } |
| 32 | 24 | ||
| 33 | is_signaled = true; | 25 | is_signaled = true; |
| 34 | SynchronizationObject::Signal(); | 26 | NotifyAvailable(); |
| 27 | } | ||
| 28 | |||
| 29 | bool ReadableEvent::IsSignaled() const { | ||
| 30 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 31 | |||
| 32 | return is_signaled; | ||
| 35 | } | 33 | } |
| 36 | 34 | ||
| 37 | void ReadableEvent::Clear() { | 35 | void ReadableEvent::Clear() { |
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 3264dd066..34e477274 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 7 | #include "core/hle/kernel/object.h" | 8 | #include "core/hle/kernel/object.h" |
| 8 | #include "core/hle/kernel/synchronization_object.h" | ||
| 9 | 9 | ||
| 10 | union ResultCode; | 10 | union ResultCode; |
| 11 | 11 | ||
| @@ -14,7 +14,7 @@ namespace Kernel { | |||
| 14 | class KernelCore; | 14 | class KernelCore; |
| 15 | class WritableEvent; | 15 | class WritableEvent; |
| 16 | 16 | ||
| 17 | class ReadableEvent final : public SynchronizationObject { | 17 | class ReadableEvent final : public KSynchronizationObject { |
| 18 | friend class WritableEvent; | 18 | friend class WritableEvent; |
| 19 | 19 | ||
| 20 | public: | 20 | public: |
| @@ -32,9 +32,6 @@ public: | |||
| 32 | return HANDLE_TYPE; | 32 | return HANDLE_TYPE; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | bool ShouldWait(const Thread* thread) const override; | ||
| 36 | void Acquire(Thread* thread) override; | ||
| 37 | |||
| 38 | /// Unconditionally clears the readable event's state. | 35 | /// Unconditionally clears the readable event's state. |
| 39 | void Clear(); | 36 | void Clear(); |
| 40 | 37 | ||
| @@ -46,11 +43,14 @@ public: | |||
| 46 | /// then ERR_INVALID_STATE will be returned. | 43 | /// then ERR_INVALID_STATE will be returned. |
| 47 | ResultCode Reset(); | 44 | ResultCode Reset(); |
| 48 | 45 | ||
| 49 | void Signal() override; | 46 | void Signal(); |
| 47 | |||
| 48 | bool IsSignaled() const override; | ||
| 50 | 49 | ||
| 51 | private: | 50 | private: |
| 52 | explicit ReadableEvent(KernelCore& kernel); | 51 | explicit ReadableEvent(KernelCore& kernel); |
| 53 | 52 | ||
| 53 | bool is_signaled{}; | ||
| 54 | std::string name; ///< Name of event (optional) | 54 | std::string name; ///< Name of event (optional) |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index a549ae9d7..82857f93b 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {} | 16 | ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 17 | ServerPort::~ServerPort() = default; | 17 | ServerPort::~ServerPort() = default; |
| 18 | 18 | ||
| 19 | ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { | 19 | ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { |
| @@ -28,15 +28,9 @@ ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { | |||
| 28 | 28 | ||
| 29 | void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { | 29 | void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { |
| 30 | pending_sessions.push_back(std::move(pending_session)); | 30 | pending_sessions.push_back(std::move(pending_session)); |
| 31 | } | 31 | if (pending_sessions.size() == 1) { |
| 32 | 32 | NotifyAvailable(); | |
| 33 | bool ServerPort::ShouldWait(const Thread* thread) const { | 33 | } |
| 34 | // If there are no pending sessions, we wait until a new one is added. | ||
| 35 | return pending_sessions.empty(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void ServerPort::Acquire(Thread* thread) { | ||
| 39 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | ||
| 40 | } | 34 | } |
| 41 | 35 | ||
| 42 | bool ServerPort::IsSignaled() const { | 36 | bool ServerPort::IsSignaled() const { |
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 41b191b86..6470df993 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h | |||
| @@ -9,8 +9,8 @@ | |||
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 12 | #include "core/hle/kernel/object.h" | 13 | #include "core/hle/kernel/object.h" |
| 13 | #include "core/hle/kernel/synchronization_object.h" | ||
| 14 | #include "core/hle/result.h" | 14 | #include "core/hle/result.h" |
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| @@ -20,7 +20,7 @@ class KernelCore; | |||
| 20 | class ServerSession; | 20 | class ServerSession; |
| 21 | class SessionRequestHandler; | 21 | class SessionRequestHandler; |
| 22 | 22 | ||
| 23 | class ServerPort final : public SynchronizationObject { | 23 | class ServerPort final : public KSynchronizationObject { |
| 24 | public: | 24 | public: |
| 25 | explicit ServerPort(KernelCore& kernel); | 25 | explicit ServerPort(KernelCore& kernel); |
| 26 | ~ServerPort() override; | 26 | ~ServerPort() override; |
| @@ -79,9 +79,6 @@ public: | |||
| 79 | /// waiting to be accepted by this port. | 79 | /// waiting to be accepted by this port. |
| 80 | void AppendPendingSession(std::shared_ptr<ServerSession> pending_session); | 80 | void AppendPendingSession(std::shared_ptr<ServerSession> pending_session); |
| 81 | 81 | ||
| 82 | bool ShouldWait(const Thread* thread) const override; | ||
| 83 | void Acquire(Thread* thread) override; | ||
| 84 | |||
| 85 | bool IsSignaled() const override; | 82 | bool IsSignaled() const override; |
| 86 | 83 | ||
| 87 | private: | 84 | private: |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index b40fe3916..4f2bb7822 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | namespace Kernel { | 25 | namespace Kernel { |
| 26 | 26 | ||
| 27 | ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} | 27 | ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 28 | 28 | ||
| 29 | ServerSession::~ServerSession() { | 29 | ServerSession::~ServerSession() { |
| 30 | kernel.ReleaseServiceThread(service_thread); | 30 | kernel.ReleaseServiceThread(service_thread); |
| @@ -42,16 +42,6 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern | |||
| 42 | return MakeResult(std::move(session)); | 42 | return MakeResult(std::move(session)); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | bool ServerSession::ShouldWait(const Thread* thread) const { | ||
| 46 | // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. | ||
| 47 | if (!parent->Client()) { | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | |||
| 51 | // Wait if we have no pending requests, or if we're currently handling a request. | ||
| 52 | return pending_requesting_threads.empty() || currently_handling != nullptr; | ||
| 53 | } | ||
| 54 | |||
| 55 | bool ServerSession::IsSignaled() const { | 45 | bool ServerSession::IsSignaled() const { |
| 56 | // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. | 46 | // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. |
| 57 | if (!parent->Client()) { | 47 | if (!parent->Client()) { |
| @@ -62,15 +52,6 @@ bool ServerSession::IsSignaled() const { | |||
| 62 | return !pending_requesting_threads.empty() && currently_handling == nullptr; | 52 | return !pending_requesting_threads.empty() && currently_handling == nullptr; |
| 63 | } | 53 | } |
| 64 | 54 | ||
| 65 | void ServerSession::Acquire(Thread* thread) { | ||
| 66 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | ||
| 67 | // We are now handling a request, pop it from the stack. | ||
| 68 | // TODO(Subv): What happens if the client endpoint is closed before any requests are made? | ||
| 69 | ASSERT(!pending_requesting_threads.empty()); | ||
| 70 | currently_handling = pending_requesting_threads.back(); | ||
| 71 | pending_requesting_threads.pop_back(); | ||
| 72 | } | ||
| 73 | |||
| 74 | void ServerSession::ClientDisconnected() { | 55 | void ServerSession::ClientDisconnected() { |
| 75 | // We keep a shared pointer to the hle handler to keep it alive throughout | 56 | // We keep a shared pointer to the hle handler to keep it alive throughout |
| 76 | // the call to ClientDisconnected, as ClientDisconnected invalidates the | 57 | // the call to ClientDisconnected, as ClientDisconnected invalidates the |
| @@ -172,7 +153,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 172 | { | 153 | { |
| 173 | KScopedSchedulerLock lock(kernel); | 154 | KScopedSchedulerLock lock(kernel); |
| 174 | if (!context.IsThreadWaiting()) { | 155 | if (!context.IsThreadWaiting()) { |
| 175 | context.GetThread().ResumeFromWait(); | 156 | context.GetThread().Wakeup(); |
| 176 | context.GetThread().SetSynchronizationResults(nullptr, result); | 157 | context.GetThread().SetSynchronizationResults(nullptr, result); |
| 177 | } | 158 | } |
| 178 | } | 159 | } |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index e8d1d99ea..9155cf7f5 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -10,8 +10,8 @@ | |||
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/threadsafe_queue.h" | 12 | #include "common/threadsafe_queue.h" |
| 13 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 13 | #include "core/hle/kernel/service_thread.h" | 14 | #include "core/hle/kernel/service_thread.h" |
| 14 | #include "core/hle/kernel/synchronization_object.h" | ||
| 15 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 16 | 16 | ||
| 17 | namespace Core::Memory { | 17 | namespace Core::Memory { |
| @@ -43,7 +43,7 @@ class Thread; | |||
| 43 | * After the server replies to the request, the response is marshalled back to the caller's | 43 | * After the server replies to the request, the response is marshalled back to the caller's |
| 44 | * TLS buffer and control is transferred back to it. | 44 | * TLS buffer and control is transferred back to it. |
| 45 | */ | 45 | */ |
| 46 | class ServerSession final : public SynchronizationObject { | 46 | class ServerSession final : public KSynchronizationObject { |
| 47 | friend class ServiceThread; | 47 | friend class ServiceThread; |
| 48 | 48 | ||
| 49 | public: | 49 | public: |
| @@ -77,8 +77,6 @@ public: | |||
| 77 | return parent.get(); | 77 | return parent.get(); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | bool IsSignaled() const override; | ||
| 81 | |||
| 82 | /** | 80 | /** |
| 83 | * Sets the HLE handler for the session. This handler will be called to service IPC requests | 81 | * Sets the HLE handler for the session. This handler will be called to service IPC requests |
| 84 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not | 82 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not |
| @@ -100,10 +98,6 @@ public: | |||
| 100 | ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, | 98 | ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory, |
| 101 | Core::Timing::CoreTiming& core_timing); | 99 | Core::Timing::CoreTiming& core_timing); |
| 102 | 100 | ||
| 103 | bool ShouldWait(const Thread* thread) const override; | ||
| 104 | |||
| 105 | void Acquire(Thread* thread) override; | ||
| 106 | |||
| 107 | /// Called when a client disconnection occurs. | 101 | /// Called when a client disconnection occurs. |
| 108 | void ClientDisconnected(); | 102 | void ClientDisconnected(); |
| 109 | 103 | ||
| @@ -130,6 +124,8 @@ public: | |||
| 130 | convert_to_domain = true; | 124 | convert_to_domain = true; |
| 131 | } | 125 | } |
| 132 | 126 | ||
| 127 | bool IsSignaled() const override; | ||
| 128 | |||
| 133 | private: | 129 | private: |
| 134 | /// Queues a sync request from the emulated application. | 130 | /// Queues a sync request from the emulated application. |
| 135 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); | 131 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); |
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index e4dd53e24..75304b961 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace Kernel { | 10 | namespace Kernel { |
| 11 | 11 | ||
| 12 | Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {} | 12 | Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 13 | Session::~Session() = default; | 13 | Session::~Session() = default; |
| 14 | 14 | ||
| 15 | Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { | 15 | Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { |
| @@ -24,18 +24,9 @@ Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { | |||
| 24 | return std::make_pair(std::move(client_session), std::move(server_session)); | 24 | return std::make_pair(std::move(client_session), std::move(server_session)); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | bool Session::ShouldWait(const Thread* thread) const { | ||
| 28 | UNIMPLEMENTED(); | ||
| 29 | return {}; | ||
| 30 | } | ||
| 31 | |||
| 32 | bool Session::IsSignaled() const { | 27 | bool Session::IsSignaled() const { |
| 33 | UNIMPLEMENTED(); | 28 | UNIMPLEMENTED(); |
| 34 | return true; | 29 | return true; |
| 35 | } | 30 | } |
| 36 | 31 | ||
| 37 | void Session::Acquire(Thread* thread) { | ||
| 38 | UNIMPLEMENTED(); | ||
| 39 | } | ||
| 40 | |||
| 41 | } // namespace Kernel | 32 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 7cd9c0d77..f6dd2c1d2 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | 10 | ||
| 11 | #include "core/hle/kernel/synchronization_object.h" | 11 | #include "core/hle/kernel/k_synchronization_object.h" |
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| @@ -19,7 +19,7 @@ class ServerSession; | |||
| 19 | * Parent structure to link the client and server endpoints of a session with their associated | 19 | * Parent structure to link the client and server endpoints of a session with their associated |
| 20 | * client port. | 20 | * client port. |
| 21 | */ | 21 | */ |
| 22 | class Session final : public SynchronizationObject { | 22 | class Session final : public KSynchronizationObject { |
| 23 | public: | 23 | public: |
| 24 | explicit Session(KernelCore& kernel); | 24 | explicit Session(KernelCore& kernel); |
| 25 | ~Session() override; | 25 | ~Session() override; |
| @@ -37,12 +37,8 @@ public: | |||
| 37 | return HANDLE_TYPE; | 37 | return HANDLE_TYPE; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | bool ShouldWait(const Thread* thread) const override; | ||
| 41 | |||
| 42 | bool IsSignaled() const override; | 40 | bool IsSignaled() const override; |
| 43 | 41 | ||
| 44 | void Acquire(Thread* thread) override; | ||
| 45 | |||
| 46 | std::shared_ptr<ClientSession> Client() { | 42 | std::shared_ptr<ClientSession> Client() { |
| 47 | if (auto result{client.lock()}) { | 43 | if (auto result{client.lock()}) { |
| 48 | return result; | 44 | return result; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index de3ed25da..0a3064c7d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "core/hle/kernel/handle_table.h" | 26 | #include "core/hle/kernel/handle_table.h" |
| 27 | #include "core/hle/kernel/k_scheduler.h" | 27 | #include "core/hle/kernel/k_scheduler.h" |
| 28 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 28 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 29 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 29 | #include "core/hle/kernel/kernel.h" | 30 | #include "core/hle/kernel/kernel.h" |
| 30 | #include "core/hle/kernel/memory/memory_block.h" | 31 | #include "core/hle/kernel/memory/memory_block.h" |
| 31 | #include "core/hle/kernel/memory/page_table.h" | 32 | #include "core/hle/kernel/memory/page_table.h" |
| @@ -38,7 +39,6 @@ | |||
| 38 | #include "core/hle/kernel/svc.h" | 39 | #include "core/hle/kernel/svc.h" |
| 39 | #include "core/hle/kernel/svc_types.h" | 40 | #include "core/hle/kernel/svc_types.h" |
| 40 | #include "core/hle/kernel/svc_wrap.h" | 41 | #include "core/hle/kernel/svc_wrap.h" |
| 41 | #include "core/hle/kernel/synchronization.h" | ||
| 42 | #include "core/hle/kernel/thread.h" | 42 | #include "core/hle/kernel/thread.h" |
| 43 | #include "core/hle/kernel/time_manager.h" | 43 | #include "core/hle/kernel/time_manager.h" |
| 44 | #include "core/hle/kernel/transfer_memory.h" | 44 | #include "core/hle/kernel/transfer_memory.h" |
| @@ -343,25 +343,14 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 343 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); | 343 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 344 | { | 344 | { |
| 345 | KScopedSchedulerLock lock(kernel); | 345 | KScopedSchedulerLock lock(kernel); |
| 346 | thread->InvalidateHLECallback(); | 346 | thread->SetState(ThreadStatus::WaitIPC); |
| 347 | thread->SetStatus(ThreadStatus::WaitIPC); | ||
| 348 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); | 347 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); |
| 349 | } | 348 | } |
| 350 | 349 | ||
| 351 | if (thread->HasHLECallback()) { | 350 | Handle event_handle = thread->GetHLETimeEvent(); |
| 352 | Handle event_handle = thread->GetHLETimeEvent(); | 351 | if (event_handle != InvalidHandle) { |
| 353 | if (event_handle != InvalidHandle) { | 352 | auto& time_manager = kernel.TimeManager(); |
| 354 | auto& time_manager = kernel.TimeManager(); | 353 | time_manager.UnscheduleTimeEvent(event_handle); |
| 355 | time_manager.UnscheduleTimeEvent(event_handle); | ||
| 356 | } | ||
| 357 | |||
| 358 | { | ||
| 359 | KScopedSchedulerLock lock(kernel); | ||
| 360 | auto* sync_object = thread->GetHLESyncObject(); | ||
| 361 | sync_object->RemoveWaitingThread(SharedFrom(thread)); | ||
| 362 | } | ||
| 363 | |||
| 364 | thread->InvokeHLECallback(SharedFrom(thread)); | ||
| 365 | } | 354 | } |
| 366 | 355 | ||
| 367 | return thread->GetSignalingResult(); | 356 | return thread->GetSignalingResult(); |
| @@ -436,7 +425,7 @@ static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* | |||
| 436 | } | 425 | } |
| 437 | 426 | ||
| 438 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 427 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 439 | static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, | 428 | static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, |
| 440 | u64 handle_count, s64 nano_seconds) { | 429 | u64 handle_count, s64 nano_seconds) { |
| 441 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", | 430 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", |
| 442 | handles_address, handle_count, nano_seconds); | 431 | handles_address, handle_count, nano_seconds); |
| @@ -458,28 +447,26 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr | |||
| 458 | } | 447 | } |
| 459 | 448 | ||
| 460 | auto& kernel = system.Kernel(); | 449 | auto& kernel = system.Kernel(); |
| 461 | Thread::ThreadSynchronizationObjects objects(handle_count); | 450 | std::vector<KSynchronizationObject*> objects(handle_count); |
| 462 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 451 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 463 | 452 | ||
| 464 | for (u64 i = 0; i < handle_count; ++i) { | 453 | for (u64 i = 0; i < handle_count; ++i) { |
| 465 | const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); | 454 | const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); |
| 466 | const auto object = handle_table.Get<SynchronizationObject>(handle); | 455 | const auto object = handle_table.Get<KSynchronizationObject>(handle); |
| 467 | 456 | ||
| 468 | if (object == nullptr) { | 457 | if (object == nullptr) { |
| 469 | LOG_ERROR(Kernel_SVC, "Object is a nullptr"); | 458 | LOG_ERROR(Kernel_SVC, "Object is a nullptr"); |
| 470 | return ERR_INVALID_HANDLE; | 459 | return ERR_INVALID_HANDLE; |
| 471 | } | 460 | } |
| 472 | 461 | ||
| 473 | objects[i] = object; | 462 | objects[i] = object.get(); |
| 474 | } | 463 | } |
| 475 | auto& synchronization = kernel.Synchronization(); | 464 | return KSynchronizationObject::Wait(kernel, index, objects.data(), |
| 476 | const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds); | 465 | static_cast<s32>(objects.size()), nano_seconds); |
| 477 | *index = handle_result; | ||
| 478 | return result; | ||
| 479 | } | 466 | } |
| 480 | 467 | ||
| 481 | static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, | 468 | static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, |
| 482 | s32 handle_count, u32 timeout_high, Handle* index) { | 469 | s32 handle_count, u32 timeout_high, s32* index) { |
| 483 | const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; | 470 | const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; |
| 484 | return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); | 471 | return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); |
| 485 | } | 472 | } |
| @@ -1655,7 +1642,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1655 | 1642 | ||
| 1656 | current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); | 1643 | current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); |
| 1657 | 1644 | ||
| 1658 | if (thread->IsPendingTermination()) { | 1645 | if (thread->IsTerminationRequested()) { |
| 1659 | lock.CancelSleep(); | 1646 | lock.CancelSleep(); |
| 1660 | return ERR_THREAD_TERMINATING; | 1647 | return ERR_THREAD_TERMINATING; |
| 1661 | } | 1648 | } |
| @@ -1674,7 +1661,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1674 | current_thread->SetCondVarWaitAddress(condition_variable_addr); | 1661 | current_thread->SetCondVarWaitAddress(condition_variable_addr); |
| 1675 | current_thread->SetMutexWaitAddress(mutex_addr); | 1662 | current_thread->SetMutexWaitAddress(mutex_addr); |
| 1676 | current_thread->SetWaitHandle(thread_handle); | 1663 | current_thread->SetWaitHandle(thread_handle); |
| 1677 | current_thread->SetStatus(ThreadStatus::WaitCondVar); | 1664 | current_thread->SetState(ThreadStatus::WaitCondVar); |
| 1678 | current_process->InsertConditionVariableThread(SharedFrom(current_thread)); | 1665 | current_process->InsertConditionVariableThread(SharedFrom(current_thread)); |
| 1679 | } | 1666 | } |
| 1680 | 1667 | ||
| @@ -1761,7 +1748,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ | |||
| 1761 | 1748 | ||
| 1762 | thread->SetLockOwner(nullptr); | 1749 | thread->SetLockOwner(nullptr); |
| 1763 | thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); | 1750 | thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); |
| 1764 | thread->ResumeFromWait(); | 1751 | thread->Wakeup(); |
| 1765 | } else { | 1752 | } else { |
| 1766 | // The mutex is already owned by some other thread, make this thread wait on it. | 1753 | // The mutex is already owned by some other thread, make this thread wait on it. |
| 1767 | const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); | 1754 | const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); |
| @@ -1769,7 +1756,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ | |||
| 1769 | auto owner = handle_table.Get<Thread>(owner_handle); | 1756 | auto owner = handle_table.Get<Thread>(owner_handle); |
| 1770 | ASSERT(owner); | 1757 | ASSERT(owner); |
| 1771 | if (thread->GetStatus() == ThreadStatus::WaitCondVar) { | 1758 | if (thread->GetStatus() == ThreadStatus::WaitCondVar) { |
| 1772 | thread->SetStatus(ThreadStatus::WaitMutex); | 1759 | thread->SetState(ThreadStatus::WaitMutex); |
| 1773 | } | 1760 | } |
| 1774 | 1761 | ||
| 1775 | owner->AddMutexWaiter(thread); | 1762 | owner->AddMutexWaiter(thread); |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 0b6dd9df0..f94c487ba 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -215,9 +215,10 @@ void SvcWrap64(Core::System& system) { | |||
| 215 | func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw); | 215 | func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | template <ResultCode func(Core::System&, u32*, u64, u64, s64)> | 218 | // Used by WaitSynchronization |
| 219 | template <ResultCode func(Core::System&, s32*, u64, u64, s64)> | ||
| 219 | void SvcWrap64(Core::System& system) { | 220 | void SvcWrap64(Core::System& system) { |
| 220 | u32 param_1 = 0; | 221 | s32 param_1 = 0; |
| 221 | const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)), | 222 | const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)), |
| 222 | static_cast<s64>(Param(system, 3))) | 223 | static_cast<s64>(Param(system, 3))) |
| 223 | .raw; | 224 | .raw; |
| @@ -539,9 +540,9 @@ void SvcWrap32(Core::System& system) { | |||
| 539 | } | 540 | } |
| 540 | 541 | ||
| 541 | // Used by WaitSynchronization32 | 542 | // Used by WaitSynchronization32 |
| 542 | template <ResultCode func(Core::System&, u32, u32, s32, u32, Handle*)> | 543 | template <ResultCode func(Core::System&, u32, u32, s32, u32, s32*)> |
| 543 | void SvcWrap32(Core::System& system) { | 544 | void SvcWrap32(Core::System& system) { |
| 544 | u32 param_1 = 0; | 545 | s32 param_1 = 0; |
| 545 | const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2), | 546 | const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2), |
| 546 | Param32(system, 3), ¶m_1) | 547 | Param32(system, 3), ¶m_1) |
| 547 | .raw; | 548 | .raw; |
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp deleted file mode 100644 index d3f520ea2..000000000 --- a/src/core/hle/kernel/synchronization.cpp +++ /dev/null | |||
| @@ -1,116 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hle/kernel/errors.h" | ||
| 7 | #include "core/hle/kernel/handle_table.h" | ||
| 8 | #include "core/hle/kernel/k_scheduler.h" | ||
| 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/synchronization.h" | ||
| 12 | #include "core/hle/kernel/synchronization_object.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | #include "core/hle/kernel/time_manager.h" | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | |||
| 18 | Synchronization::Synchronization(Core::System& system) : system{system} {} | ||
| 19 | |||
| 20 | void Synchronization::SignalObject(SynchronizationObject& obj) const { | ||
| 21 | auto& kernel = system.Kernel(); | ||
| 22 | KScopedSchedulerLock lock(kernel); | ||
| 23 | if (obj.IsSignaled()) { | ||
| 24 | for (auto thread : obj.GetWaitingThreads()) { | ||
| 25 | if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { | ||
| 26 | if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) { | ||
| 27 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); | ||
| 28 | ASSERT(thread->IsWaitingSync()); | ||
| 29 | } | ||
| 30 | thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); | ||
| 31 | thread->ResumeFromWait(); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | obj.ClearWaitingThreads(); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | std::pair<ResultCode, Handle> Synchronization::WaitFor( | ||
| 39 | std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { | ||
| 40 | auto& kernel = system.Kernel(); | ||
| 41 | auto* const thread = kernel.CurrentScheduler()->GetCurrentThread(); | ||
| 42 | Handle event_handle = InvalidHandle; | ||
| 43 | { | ||
| 44 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); | ||
| 45 | const auto itr = | ||
| 46 | std::find_if(sync_objects.begin(), sync_objects.end(), | ||
| 47 | [thread](const std::shared_ptr<SynchronizationObject>& object) { | ||
| 48 | return object->IsSignaled(); | ||
| 49 | }); | ||
| 50 | |||
| 51 | if (itr != sync_objects.end()) { | ||
| 52 | // We found a ready object, acquire it and set the result value | ||
| 53 | SynchronizationObject* object = itr->get(); | ||
| 54 | object->Acquire(thread); | ||
| 55 | const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); | ||
| 56 | lock.CancelSleep(); | ||
| 57 | return {RESULT_SUCCESS, index}; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (nano_seconds == 0) { | ||
| 61 | lock.CancelSleep(); | ||
| 62 | return {RESULT_TIMEOUT, InvalidHandle}; | ||
| 63 | } | ||
| 64 | |||
| 65 | if (thread->IsPendingTermination()) { | ||
| 66 | lock.CancelSleep(); | ||
| 67 | return {ERR_THREAD_TERMINATING, InvalidHandle}; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (thread->IsSyncCancelled()) { | ||
| 71 | thread->SetSyncCancelled(false); | ||
| 72 | lock.CancelSleep(); | ||
| 73 | return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; | ||
| 74 | } | ||
| 75 | |||
| 76 | for (auto& object : sync_objects) { | ||
| 77 | object->AddWaitingThread(SharedFrom(thread)); | ||
| 78 | } | ||
| 79 | |||
| 80 | thread->SetSynchronizationObjects(&sync_objects); | ||
| 81 | thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); | ||
| 82 | thread->SetStatus(ThreadStatus::WaitSynch); | ||
| 83 | thread->SetWaitingSync(true); | ||
| 84 | } | ||
| 85 | thread->SetWaitingSync(false); | ||
| 86 | |||
| 87 | if (event_handle != InvalidHandle) { | ||
| 88 | auto& time_manager = kernel.TimeManager(); | ||
| 89 | time_manager.UnscheduleTimeEvent(event_handle); | ||
| 90 | } | ||
| 91 | |||
| 92 | { | ||
| 93 | KScopedSchedulerLock lock(kernel); | ||
| 94 | ResultCode signaling_result = thread->GetSignalingResult(); | ||
| 95 | SynchronizationObject* signaling_object = thread->GetSignalingObject(); | ||
| 96 | thread->SetSynchronizationObjects(nullptr); | ||
| 97 | auto shared_thread = SharedFrom(thread); | ||
| 98 | for (auto& obj : sync_objects) { | ||
| 99 | obj->RemoveWaitingThread(shared_thread); | ||
| 100 | } | ||
| 101 | if (signaling_object != nullptr) { | ||
| 102 | const auto itr = std::find_if( | ||
| 103 | sync_objects.begin(), sync_objects.end(), | ||
| 104 | [signaling_object](const std::shared_ptr<SynchronizationObject>& object) { | ||
| 105 | return object.get() == signaling_object; | ||
| 106 | }); | ||
| 107 | ASSERT(itr != sync_objects.end()); | ||
| 108 | signaling_object->Acquire(thread); | ||
| 109 | const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); | ||
| 110 | return {signaling_result, index}; | ||
| 111 | } | ||
| 112 | return {signaling_result, -1}; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h deleted file mode 100644 index 379f4b1d3..000000000 --- a/src/core/hle/kernel/synchronization.h +++ /dev/null | |||
| @@ -1,44 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <utility> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | } // namespace Core | ||
| 17 | |||
| 18 | namespace Kernel { | ||
| 19 | |||
| 20 | class SynchronizationObject; | ||
| 21 | |||
| 22 | /** | ||
| 23 | * The 'Synchronization' class is an interface for handling synchronization methods | ||
| 24 | * used by Synchronization objects and synchronization SVCs. This centralizes processing of | ||
| 25 | * such | ||
| 26 | */ | ||
| 27 | class Synchronization { | ||
| 28 | public: | ||
| 29 | explicit Synchronization(Core::System& system); | ||
| 30 | |||
| 31 | /// Signals a synchronization object, waking up all its waiting threads | ||
| 32 | void SignalObject(SynchronizationObject& obj) const; | ||
| 33 | |||
| 34 | /// Tries to see if waiting for any of the sync_objects is necessary, if not | ||
| 35 | /// it returns Success and the handle index of the signaled sync object. In | ||
| 36 | /// case not, the current thread will be locked and wait for nano_seconds or | ||
| 37 | /// for a synchronization object to signal. | ||
| 38 | std::pair<ResultCode, Handle> WaitFor( | ||
| 39 | std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds); | ||
| 40 | |||
| 41 | private: | ||
| 42 | Core::System& system; | ||
| 43 | }; | ||
| 44 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp deleted file mode 100644 index ba4d39157..000000000 --- a/src/core/hle/kernel/synchronization_object.cpp +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | #include "core/hle/kernel/process.h" | ||
| 13 | #include "core/hle/kernel/synchronization.h" | ||
| 14 | #include "core/hle/kernel/synchronization_object.h" | ||
| 15 | #include "core/hle/kernel/thread.h" | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} | ||
| 20 | SynchronizationObject::~SynchronizationObject() = default; | ||
| 21 | |||
| 22 | void SynchronizationObject::Signal() { | ||
| 23 | kernel.Synchronization().SignalObject(*this); | ||
| 24 | } | ||
| 25 | |||
| 26 | void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) { | ||
| 27 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | ||
| 28 | if (itr == waiting_threads.end()) | ||
| 29 | waiting_threads.push_back(std::move(thread)); | ||
| 30 | } | ||
| 31 | |||
| 32 | void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { | ||
| 33 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | ||
| 34 | // If a thread passed multiple handles to the same object, | ||
| 35 | // the kernel might attempt to remove the thread from the object's | ||
| 36 | // waiting threads list multiple times. | ||
| 37 | if (itr != waiting_threads.end()) | ||
| 38 | waiting_threads.erase(itr); | ||
| 39 | } | ||
| 40 | |||
| 41 | void SynchronizationObject::ClearWaitingThreads() { | ||
| 42 | waiting_threads.clear(); | ||
| 43 | } | ||
| 44 | |||
| 45 | const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const { | ||
| 46 | return waiting_threads; | ||
| 47 | } | ||
| 48 | |||
| 49 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h deleted file mode 100644 index 7408ed51f..000000000 --- a/src/core/hle/kernel/synchronization_object.h +++ /dev/null | |||
| @@ -1,77 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <memory> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | class KernelCore; | ||
| 16 | class Synchronization; | ||
| 17 | class Thread; | ||
| 18 | |||
| 19 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 20 | class SynchronizationObject : public Object { | ||
| 21 | public: | ||
| 22 | explicit SynchronizationObject(KernelCore& kernel); | ||
| 23 | ~SynchronizationObject() override; | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Check if the specified thread should wait until the object is available | ||
| 27 | * @param thread The thread about which we're deciding. | ||
| 28 | * @return True if the current thread should wait due to this object being unavailable | ||
| 29 | */ | ||
| 30 | virtual bool ShouldWait(const Thread* thread) const = 0; | ||
| 31 | |||
| 32 | /// Acquire/lock the object for the specified thread if it is available | ||
| 33 | virtual void Acquire(Thread* thread) = 0; | ||
| 34 | |||
| 35 | /// Signal this object | ||
| 36 | virtual void Signal(); | ||
| 37 | |||
| 38 | virtual bool IsSignaled() const { | ||
| 39 | return is_signaled; | ||
| 40 | } | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Add a thread to wait on this object | ||
| 44 | * @param thread Pointer to thread to add | ||
| 45 | */ | ||
| 46 | void AddWaitingThread(std::shared_ptr<Thread> thread); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Removes a thread from waiting on this object (e.g. if it was resumed already) | ||
| 50 | * @param thread Pointer to thread to remove | ||
| 51 | */ | ||
| 52 | void RemoveWaitingThread(std::shared_ptr<Thread> thread); | ||
| 53 | |||
| 54 | /// Get a const reference to the waiting threads list for debug use | ||
| 55 | const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; | ||
| 56 | |||
| 57 | void ClearWaitingThreads(); | ||
| 58 | |||
| 59 | protected: | ||
| 60 | std::atomic_bool is_signaled{}; // Tells if this sync object is signaled | ||
| 61 | |||
| 62 | private: | ||
| 63 | /// Threads waiting for this object to become available | ||
| 64 | std::vector<std::shared_ptr<Thread>> waiting_threads; | ||
| 65 | }; | ||
| 66 | |||
| 67 | // Specialization of DynamicObjectCast for SynchronizationObjects | ||
| 68 | template <> | ||
| 69 | inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>( | ||
| 70 | std::shared_ptr<Object> object) { | ||
| 71 | if (object != nullptr && object->IsWaitable()) { | ||
| 72 | return std::static_pointer_cast<SynchronizationObject>(object); | ||
| 73 | } | ||
| 74 | return nullptr; | ||
| 75 | } | ||
| 76 | |||
| 77 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a4f9e0d97..ac19e2997 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -34,26 +34,19 @@ | |||
| 34 | 34 | ||
| 35 | namespace Kernel { | 35 | namespace Kernel { |
| 36 | 36 | ||
| 37 | bool Thread::ShouldWait(const Thread* thread) const { | ||
| 38 | return status != ThreadStatus::Dead; | ||
| 39 | } | ||
| 40 | |||
| 41 | bool Thread::IsSignaled() const { | 37 | bool Thread::IsSignaled() const { |
| 42 | return status == ThreadStatus::Dead; | 38 | return signaled; |
| 43 | } | 39 | } |
| 44 | 40 | ||
| 45 | void Thread::Acquire(Thread* thread) { | 41 | Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 46 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | ||
| 47 | } | ||
| 48 | |||
| 49 | Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} | ||
| 50 | Thread::~Thread() = default; | 42 | Thread::~Thread() = default; |
| 51 | 43 | ||
| 52 | void Thread::Stop() { | 44 | void Thread::Stop() { |
| 53 | { | 45 | { |
| 54 | KScopedSchedulerLock lock(kernel); | 46 | KScopedSchedulerLock lock(kernel); |
| 55 | SetStatus(ThreadStatus::Dead); | 47 | SetState(ThreadStatus::Dead); |
| 56 | Signal(); | 48 | signaled = true; |
| 49 | NotifyAvailable(); | ||
| 57 | kernel.GlobalHandleTable().Close(global_handle); | 50 | kernel.GlobalHandleTable().Close(global_handle); |
| 58 | 51 | ||
| 59 | if (owner_process) { | 52 | if (owner_process) { |
| @@ -67,7 +60,7 @@ void Thread::Stop() { | |||
| 67 | global_handle = 0; | 60 | global_handle = 0; |
| 68 | } | 61 | } |
| 69 | 62 | ||
| 70 | void Thread::ResumeFromWait() { | 63 | void Thread::Wakeup() { |
| 71 | KScopedSchedulerLock lock(kernel); | 64 | KScopedSchedulerLock lock(kernel); |
| 72 | switch (status) { | 65 | switch (status) { |
| 73 | case ThreadStatus::Paused: | 66 | case ThreadStatus::Paused: |
| @@ -82,9 +75,6 @@ void Thread::ResumeFromWait() { | |||
| 82 | break; | 75 | break; |
| 83 | 76 | ||
| 84 | case ThreadStatus::Ready: | 77 | case ThreadStatus::Ready: |
| 85 | // The thread's wakeup callback must have already been cleared when the thread was first | ||
| 86 | // awoken. | ||
| 87 | ASSERT(hle_callback == nullptr); | ||
| 88 | // If the thread is waiting on multiple wait objects, it might be awoken more than once | 78 | // If the thread is waiting on multiple wait objects, it might be awoken more than once |
| 89 | // before actually resuming. We can ignore subsequent wakeups if the thread status has | 79 | // before actually resuming. We can ignore subsequent wakeups if the thread status has |
| 90 | // already been set to ThreadStatus::Ready. | 80 | // already been set to ThreadStatus::Ready. |
| @@ -96,30 +86,30 @@ void Thread::ResumeFromWait() { | |||
| 96 | return; | 86 | return; |
| 97 | } | 87 | } |
| 98 | 88 | ||
| 99 | SetStatus(ThreadStatus::Ready); | 89 | SetState(ThreadStatus::Ready); |
| 100 | } | 90 | } |
| 101 | 91 | ||
| 102 | void Thread::OnWakeUp() { | 92 | void Thread::OnWakeUp() { |
| 103 | KScopedSchedulerLock lock(kernel); | 93 | KScopedSchedulerLock lock(kernel); |
| 104 | SetStatus(ThreadStatus::Ready); | 94 | SetState(ThreadStatus::Ready); |
| 105 | } | 95 | } |
| 106 | 96 | ||
| 107 | ResultCode Thread::Start() { | 97 | ResultCode Thread::Start() { |
| 108 | KScopedSchedulerLock lock(kernel); | 98 | KScopedSchedulerLock lock(kernel); |
| 109 | SetStatus(ThreadStatus::Ready); | 99 | SetState(ThreadStatus::Ready); |
| 110 | return RESULT_SUCCESS; | 100 | return RESULT_SUCCESS; |
| 111 | } | 101 | } |
| 112 | 102 | ||
| 113 | void Thread::CancelWait() { | 103 | void Thread::CancelWait() { |
| 114 | KScopedSchedulerLock lock(kernel); | 104 | KScopedSchedulerLock lock(kernel); |
| 115 | if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { | 105 | if (GetState() != ThreadSchedStatus::Paused || !is_cancellable) { |
| 116 | is_sync_cancelled = true; | 106 | is_sync_cancelled = true; |
| 117 | return; | 107 | return; |
| 118 | } | 108 | } |
| 119 | // TODO(Blinkhawk): Implement cancel of server session | 109 | // TODO(Blinkhawk): Implement cancel of server session |
| 120 | is_sync_cancelled = false; | 110 | is_sync_cancelled = false; |
| 121 | SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); | 111 | SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); |
| 122 | SetStatus(ThreadStatus::Ready); | 112 | SetState(ThreadStatus::Ready); |
| 123 | } | 113 | } |
| 124 | 114 | ||
| 125 | static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, | 115 | static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, |
| @@ -194,7 +184,6 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 194 | thread->processor_id = processor_id; | 184 | thread->processor_id = processor_id; |
| 195 | thread->ideal_core = processor_id; | 185 | thread->ideal_core = processor_id; |
| 196 | thread->affinity_mask.SetAffinity(processor_id, true); | 186 | thread->affinity_mask.SetAffinity(processor_id, true); |
| 197 | thread->wait_objects = nullptr; | ||
| 198 | thread->mutex_wait_address = 0; | 187 | thread->mutex_wait_address = 0; |
| 199 | thread->condvar_wait_address = 0; | 188 | thread->condvar_wait_address = 0; |
| 200 | thread->wait_handle = 0; | 189 | thread->wait_handle = 0; |
| @@ -202,6 +191,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 202 | thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); | 191 | thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); |
| 203 | thread->owner_process = owner_process; | 192 | thread->owner_process = owner_process; |
| 204 | thread->type = type_flags; | 193 | thread->type = type_flags; |
| 194 | thread->signaled = false; | ||
| 205 | if ((type_flags & THREADTYPE_IDLE) == 0) { | 195 | if ((type_flags & THREADTYPE_IDLE) == 0) { |
| 206 | auto& scheduler = kernel.GlobalSchedulerContext(); | 196 | auto& scheduler = kernel.GlobalSchedulerContext(); |
| 207 | scheduler.AddThread(thread); | 197 | scheduler.AddThread(thread); |
| @@ -234,24 +224,18 @@ void Thread::SetPriority(u32 priority) { | |||
| 234 | UpdatePriority(); | 224 | UpdatePriority(); |
| 235 | } | 225 | } |
| 236 | 226 | ||
| 237 | void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { | 227 | void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) { |
| 238 | signaling_object = object; | 228 | signaling_object = object; |
| 239 | signaling_result = result; | 229 | signaling_result = result; |
| 240 | } | 230 | } |
| 241 | 231 | ||
| 242 | s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const { | ||
| 243 | ASSERT_MSG(!wait_objects->empty(), "Thread is not waiting for anything"); | ||
| 244 | const auto match = std::find(wait_objects->rbegin(), wait_objects->rend(), object); | ||
| 245 | return static_cast<s32>(std::distance(match, wait_objects->rend()) - 1); | ||
| 246 | } | ||
| 247 | |||
| 248 | VAddr Thread::GetCommandBufferAddress() const { | 232 | VAddr Thread::GetCommandBufferAddress() const { |
| 249 | // Offset from the start of TLS at which the IPC command buffer begins. | 233 | // Offset from the start of TLS at which the IPC command buffer begins. |
| 250 | constexpr u64 command_header_offset = 0x80; | 234 | constexpr u64 command_header_offset = 0x80; |
| 251 | return GetTLSAddress() + command_header_offset; | 235 | return GetTLSAddress() + command_header_offset; |
| 252 | } | 236 | } |
| 253 | 237 | ||
| 254 | void Thread::SetStatus(ThreadStatus new_status) { | 238 | void Thread::SetState(ThreadStatus new_status) { |
| 255 | if (new_status == status) { | 239 | if (new_status == status) { |
| 256 | return; | 240 | return; |
| 257 | } | 241 | } |
| @@ -351,28 +335,16 @@ void Thread::UpdatePriority() { | |||
| 351 | lock_owner->UpdatePriority(); | 335 | lock_owner->UpdatePriority(); |
| 352 | } | 336 | } |
| 353 | 337 | ||
| 354 | bool Thread::AllSynchronizationObjectsReady() const { | ||
| 355 | return std::none_of(wait_objects->begin(), wait_objects->end(), | ||
| 356 | [this](const std::shared_ptr<SynchronizationObject>& object) { | ||
| 357 | return object->ShouldWait(this); | ||
| 358 | }); | ||
| 359 | } | ||
| 360 | |||
| 361 | bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) { | ||
| 362 | ASSERT(hle_callback); | ||
| 363 | return hle_callback(std::move(thread)); | ||
| 364 | } | ||
| 365 | |||
| 366 | ResultCode Thread::SetActivity(ThreadActivity value) { | 338 | ResultCode Thread::SetActivity(ThreadActivity value) { |
| 367 | KScopedSchedulerLock lock(kernel); | 339 | KScopedSchedulerLock lock(kernel); |
| 368 | 340 | ||
| 369 | auto sched_status = GetSchedulingStatus(); | 341 | auto sched_status = GetState(); |
| 370 | 342 | ||
| 371 | if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { | 343 | if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { |
| 372 | return ERR_INVALID_STATE; | 344 | return ERR_INVALID_STATE; |
| 373 | } | 345 | } |
| 374 | 346 | ||
| 375 | if (IsPendingTermination()) { | 347 | if (IsTerminationRequested()) { |
| 376 | return RESULT_SUCCESS; | 348 | return RESULT_SUCCESS; |
| 377 | } | 349 | } |
| 378 | 350 | ||
| @@ -394,7 +366,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { | |||
| 394 | Handle event_handle{}; | 366 | Handle event_handle{}; |
| 395 | { | 367 | { |
| 396 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); | 368 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); |
| 397 | SetStatus(ThreadStatus::WaitSleep); | 369 | SetState(ThreadStatus::WaitSleep); |
| 398 | } | 370 | } |
| 399 | 371 | ||
| 400 | if (event_handle != InvalidHandle) { | 372 | if (event_handle != InvalidHandle) { |
| @@ -407,7 +379,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { | |||
| 407 | void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { | 379 | void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { |
| 408 | const u32 old_state = scheduling_state; | 380 | const u32 old_state = scheduling_state; |
| 409 | pausing_state |= static_cast<u32>(flag); | 381 | pausing_state |= static_cast<u32>(flag); |
| 410 | const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); | 382 | const u32 base_scheduling = static_cast<u32>(GetState()); |
| 411 | scheduling_state = base_scheduling | pausing_state; | 383 | scheduling_state = base_scheduling | pausing_state; |
| 412 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | 384 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 413 | } | 385 | } |
| @@ -415,7 +387,7 @@ void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { | |||
| 415 | void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { | 387 | void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { |
| 416 | const u32 old_state = scheduling_state; | 388 | const u32 old_state = scheduling_state; |
| 417 | pausing_state &= ~static_cast<u32>(flag); | 389 | pausing_state &= ~static_cast<u32>(flag); |
| 418 | const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); | 390 | const u32 base_scheduling = static_cast<u32>(GetState()); |
| 419 | scheduling_state = base_scheduling | pausing_state; | 391 | scheduling_state = base_scheduling | pausing_state; |
| 420 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | 392 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 421 | } | 393 | } |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 11ef29888..69458548b 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -14,8 +14,8 @@ | |||
| 14 | #include "common/spin_lock.h" | 14 | #include "common/spin_lock.h" |
| 15 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/hle/kernel/k_affinity_mask.h" | 16 | #include "core/hle/kernel/k_affinity_mask.h" |
| 17 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 17 | #include "core/hle/kernel/object.h" | 18 | #include "core/hle/kernel/object.h" |
| 18 | #include "core/hle/kernel/synchronization_object.h" | ||
| 19 | #include "core/hle/result.h" | 19 | #include "core/hle/result.h" |
| 20 | 20 | ||
| 21 | namespace Common { | 21 | namespace Common { |
| @@ -117,7 +117,7 @@ enum class ThreadSchedMasks : u32 { | |||
| 117 | ForcePauseMask = 0x0070, | 117 | ForcePauseMask = 0x0070, |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | class Thread final : public SynchronizationObject { | 120 | class Thread final : public KSynchronizationObject { |
| 121 | public: | 121 | public: |
| 122 | explicit Thread(KernelCore& kernel); | 122 | explicit Thread(KernelCore& kernel); |
| 123 | ~Thread() override; | 123 | ~Thread() override; |
| @@ -127,10 +127,6 @@ public: | |||
| 127 | using ThreadContext32 = Core::ARM_Interface::ThreadContext32; | 127 | using ThreadContext32 = Core::ARM_Interface::ThreadContext32; |
| 128 | using ThreadContext64 = Core::ARM_Interface::ThreadContext64; | 128 | using ThreadContext64 = Core::ARM_Interface::ThreadContext64; |
| 129 | 129 | ||
| 130 | using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>; | ||
| 131 | |||
| 132 | using HLECallback = std::function<bool(std::shared_ptr<Thread> thread)>; | ||
| 133 | |||
| 134 | /** | 130 | /** |
| 135 | * Creates and returns a new thread. The new thread is immediately scheduled | 131 | * Creates and returns a new thread. The new thread is immediately scheduled |
| 136 | * @param system The instance of the whole system | 132 | * @param system The instance of the whole system |
| @@ -186,10 +182,6 @@ public: | |||
| 186 | return HANDLE_TYPE; | 182 | return HANDLE_TYPE; |
| 187 | } | 183 | } |
| 188 | 184 | ||
| 189 | bool ShouldWait(const Thread* thread) const override; | ||
| 190 | void Acquire(Thread* thread) override; | ||
| 191 | bool IsSignaled() const override; | ||
| 192 | |||
| 193 | /** | 185 | /** |
| 194 | * Gets the thread's current priority | 186 | * Gets the thread's current priority |
| 195 | * @return The current thread's priority | 187 | * @return The current thread's priority |
| @@ -233,12 +225,14 @@ public: | |||
| 233 | } | 225 | } |
| 234 | 226 | ||
| 235 | /// Resumes a thread from waiting | 227 | /// Resumes a thread from waiting |
| 236 | void ResumeFromWait(); | 228 | void Wakeup(); |
| 237 | 229 | ||
| 238 | void OnWakeUp(); | 230 | void OnWakeUp(); |
| 239 | 231 | ||
| 240 | ResultCode Start(); | 232 | ResultCode Start(); |
| 241 | 233 | ||
| 234 | virtual bool IsSignaled() const override; | ||
| 235 | |||
| 242 | /// Cancels a waiting operation that this thread may or may not be within. | 236 | /// Cancels a waiting operation that this thread may or may not be within. |
| 243 | /// | 237 | /// |
| 244 | /// When the thread is within a waiting state, this will set the thread's | 238 | /// When the thread is within a waiting state, this will set the thread's |
| @@ -247,29 +241,20 @@ public: | |||
| 247 | /// | 241 | /// |
| 248 | void CancelWait(); | 242 | void CancelWait(); |
| 249 | 243 | ||
| 250 | void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); | 244 | void SetSynchronizationResults(KSynchronizationObject* object, ResultCode result); |
| 251 | 245 | ||
| 252 | SynchronizationObject* GetSignalingObject() const { | 246 | void SetSyncedObject(KSynchronizationObject* object, ResultCode result) { |
| 253 | return signaling_object; | 247 | SetSynchronizationResults(object, result); |
| 254 | } | 248 | } |
| 255 | 249 | ||
| 256 | ResultCode GetSignalingResult() const { | 250 | ResultCode GetWaitResult(KSynchronizationObject** out) const { |
| 251 | *out = this->signaling_object; | ||
| 257 | return signaling_result; | 252 | return signaling_result; |
| 258 | } | 253 | } |
| 259 | 254 | ||
| 260 | /** | 255 | ResultCode GetSignalingResult() const { |
| 261 | * Retrieves the index that this particular object occupies in the list of objects | 256 | return signaling_result; |
| 262 | * that the thread passed to WaitSynchronization, starting the search from the last element. | 257 | } |
| 263 | * | ||
| 264 | * It is used to set the output index of WaitSynchronization when the thread is awakened. | ||
| 265 | * | ||
| 266 | * When a thread wakes up due to an object signal, the kernel will use the index of the last | ||
| 267 | * matching object in the wait objects list in case of having multiple instances of the same | ||
| 268 | * object in the list. | ||
| 269 | * | ||
| 270 | * @param object Object to query the index of. | ||
| 271 | */ | ||
| 272 | s32 GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const; | ||
| 273 | 258 | ||
| 274 | /** | 259 | /** |
| 275 | * Stops a thread, invalidating it from further use | 260 | * Stops a thread, invalidating it from further use |
| @@ -345,7 +330,7 @@ public: | |||
| 345 | return status; | 330 | return status; |
| 346 | } | 331 | } |
| 347 | 332 | ||
| 348 | void SetStatus(ThreadStatus new_status); | 333 | void SetState(ThreadStatus new_status); |
| 349 | 334 | ||
| 350 | s64 GetLastScheduledTick() const { | 335 | s64 GetLastScheduledTick() const { |
| 351 | return this->last_scheduled_tick; | 336 | return this->last_scheduled_tick; |
| @@ -387,24 +372,6 @@ public: | |||
| 387 | return owner_process; | 372 | return owner_process; |
| 388 | } | 373 | } |
| 389 | 374 | ||
| 390 | const ThreadSynchronizationObjects& GetSynchronizationObjects() const { | ||
| 391 | return *wait_objects; | ||
| 392 | } | ||
| 393 | |||
| 394 | void SetSynchronizationObjects(ThreadSynchronizationObjects* objects) { | ||
| 395 | wait_objects = objects; | ||
| 396 | } | ||
| 397 | |||
| 398 | void ClearSynchronizationObjects() { | ||
| 399 | for (const auto& waiting_object : *wait_objects) { | ||
| 400 | waiting_object->RemoveWaitingThread(SharedFrom(this)); | ||
| 401 | } | ||
| 402 | wait_objects->clear(); | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Determines whether all the objects this thread is waiting on are ready. | ||
| 406 | bool AllSynchronizationObjectsReady() const; | ||
| 407 | |||
| 408 | const MutexWaitingThreads& GetMutexWaitingThreads() const { | 375 | const MutexWaitingThreads& GetMutexWaitingThreads() const { |
| 409 | return wait_mutex_threads; | 376 | return wait_mutex_threads; |
| 410 | } | 377 | } |
| @@ -449,34 +416,14 @@ public: | |||
| 449 | arb_wait_address = address; | 416 | arb_wait_address = address; |
| 450 | } | 417 | } |
| 451 | 418 | ||
| 452 | bool HasHLECallback() const { | ||
| 453 | return hle_callback != nullptr; | ||
| 454 | } | ||
| 455 | |||
| 456 | void SetHLECallback(HLECallback callback) { | ||
| 457 | hle_callback = std::move(callback); | ||
| 458 | } | ||
| 459 | |||
| 460 | void SetHLETimeEvent(Handle time_event) { | 419 | void SetHLETimeEvent(Handle time_event) { |
| 461 | hle_time_event = time_event; | 420 | hle_time_event = time_event; |
| 462 | } | 421 | } |
| 463 | 422 | ||
| 464 | void SetHLESyncObject(SynchronizationObject* object) { | ||
| 465 | hle_object = object; | ||
| 466 | } | ||
| 467 | |||
| 468 | Handle GetHLETimeEvent() const { | 423 | Handle GetHLETimeEvent() const { |
| 469 | return hle_time_event; | 424 | return hle_time_event; |
| 470 | } | 425 | } |
| 471 | 426 | ||
| 472 | SynchronizationObject* GetHLESyncObject() const { | ||
| 473 | return hle_object; | ||
| 474 | } | ||
| 475 | |||
| 476 | void InvalidateHLECallback() { | ||
| 477 | SetHLECallback(nullptr); | ||
| 478 | } | ||
| 479 | |||
| 480 | bool InvokeHLECallback(std::shared_ptr<Thread> thread); | 427 | bool InvokeHLECallback(std::shared_ptr<Thread> thread); |
| 481 | 428 | ||
| 482 | u32 GetIdealCore() const { | 429 | u32 GetIdealCore() const { |
| @@ -500,7 +447,7 @@ public: | |||
| 500 | this->schedule_count = count; | 447 | this->schedule_count = count; |
| 501 | } | 448 | } |
| 502 | 449 | ||
| 503 | ThreadSchedStatus GetSchedulingStatus() const { | 450 | ThreadSchedStatus GetState() const { |
| 504 | return static_cast<ThreadSchedStatus>(scheduling_state & | 451 | return static_cast<ThreadSchedStatus>(scheduling_state & |
| 505 | static_cast<u32>(ThreadSchedMasks::LowMask)); | 452 | static_cast<u32>(ThreadSchedMasks::LowMask)); |
| 506 | } | 453 | } |
| @@ -517,12 +464,12 @@ public: | |||
| 517 | is_running = value; | 464 | is_running = value; |
| 518 | } | 465 | } |
| 519 | 466 | ||
| 520 | bool IsSyncCancelled() const { | 467 | bool IsWaitCancelled() const { |
| 521 | return is_sync_cancelled; | 468 | return is_sync_cancelled; |
| 522 | } | 469 | } |
| 523 | 470 | ||
| 524 | void SetSyncCancelled(bool value) { | 471 | void ClearWaitCancelled() { |
| 525 | is_sync_cancelled = value; | 472 | is_sync_cancelled = false; |
| 526 | } | 473 | } |
| 527 | 474 | ||
| 528 | Handle GetGlobalHandle() const { | 475 | Handle GetGlobalHandle() const { |
| @@ -537,16 +484,20 @@ public: | |||
| 537 | waiting_for_arbitration = set; | 484 | waiting_for_arbitration = set; |
| 538 | } | 485 | } |
| 539 | 486 | ||
| 540 | bool IsWaitingSync() const { | 487 | bool IsCancellable() const { |
| 541 | return is_waiting_on_sync; | 488 | return is_cancellable; |
| 542 | } | 489 | } |
| 543 | 490 | ||
| 544 | void SetWaitingSync(bool is_waiting) { | 491 | void SetCancellable() { |
| 545 | is_waiting_on_sync = is_waiting; | 492 | is_cancellable = true; |
| 546 | } | 493 | } |
| 547 | 494 | ||
| 548 | bool IsPendingTermination() const { | 495 | void ClearCancellable() { |
| 549 | return will_be_terminated || GetSchedulingStatus() == ThreadSchedStatus::Exited; | 496 | is_cancellable = false; |
| 497 | } | ||
| 498 | |||
| 499 | bool IsTerminationRequested() const { | ||
| 500 | return will_be_terminated || GetState() == ThreadSchedStatus::Exited; | ||
| 550 | } | 501 | } |
| 551 | 502 | ||
| 552 | bool IsPaused() const { | 503 | bool IsPaused() const { |
| @@ -622,6 +573,18 @@ public: | |||
| 622 | disable_count--; | 573 | disable_count--; |
| 623 | } | 574 | } |
| 624 | 575 | ||
| 576 | void SetWaitObjectsForDebugging(KSynchronizationObject** objects, s32 num_objects) { | ||
| 577 | wait_objects_for_debugging.clear(); | ||
| 578 | wait_objects_for_debugging.reserve(num_objects); | ||
| 579 | for (auto i = 0; i < num_objects; ++i) { | ||
| 580 | wait_objects_for_debugging.emplace_back(objects[i]); | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const { | ||
| 585 | return wait_objects_for_debugging; | ||
| 586 | } | ||
| 587 | |||
| 625 | private: | 588 | private: |
| 626 | friend class GlobalSchedulerContext; | 589 | friend class GlobalSchedulerContext; |
| 627 | friend class KScheduler; | 590 | friend class KScheduler; |
| @@ -630,7 +593,6 @@ private: | |||
| 630 | void SetSchedulingStatus(ThreadSchedStatus new_status); | 593 | void SetSchedulingStatus(ThreadSchedStatus new_status); |
| 631 | void AddSchedulingFlag(ThreadSchedFlags flag); | 594 | void AddSchedulingFlag(ThreadSchedFlags flag); |
| 632 | void RemoveSchedulingFlag(ThreadSchedFlags flag); | 595 | void RemoveSchedulingFlag(ThreadSchedFlags flag); |
| 633 | |||
| 634 | void SetCurrentPriority(u32 new_priority); | 596 | void SetCurrentPriority(u32 new_priority); |
| 635 | 597 | ||
| 636 | Common::SpinLock context_guard{}; | 598 | Common::SpinLock context_guard{}; |
| @@ -671,10 +633,10 @@ private: | |||
| 671 | Process* owner_process; | 633 | Process* owner_process; |
| 672 | 634 | ||
| 673 | /// Objects that the thread is waiting on, in the same order as they were | 635 | /// Objects that the thread is waiting on, in the same order as they were |
| 674 | /// passed to WaitSynchronization. | 636 | /// passed to WaitSynchronization. This is used for debugging only. |
| 675 | ThreadSynchronizationObjects* wait_objects; | 637 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; |
| 676 | 638 | ||
| 677 | SynchronizationObject* signaling_object; | 639 | KSynchronizationObject* signaling_object; |
| 678 | ResultCode signaling_result{RESULT_SUCCESS}; | 640 | ResultCode signaling_result{RESULT_SUCCESS}; |
| 679 | 641 | ||
| 680 | /// List of threads that are waiting for a mutex that is held by this thread. | 642 | /// List of threads that are waiting for a mutex that is held by this thread. |
| @@ -697,10 +659,7 @@ private: | |||
| 697 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | 659 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. |
| 698 | Handle global_handle = 0; | 660 | Handle global_handle = 0; |
| 699 | 661 | ||
| 700 | /// Callback for HLE Events | ||
| 701 | HLECallback hle_callback; | ||
| 702 | Handle hle_time_event; | 662 | Handle hle_time_event; |
| 703 | SynchronizationObject* hle_object; | ||
| 704 | 663 | ||
| 705 | KScheduler* scheduler = nullptr; | 664 | KScheduler* scheduler = nullptr; |
| 706 | 665 | ||
| @@ -714,7 +673,7 @@ private: | |||
| 714 | 673 | ||
| 715 | u32 pausing_state = 0; | 674 | u32 pausing_state = 0; |
| 716 | bool is_running = false; | 675 | bool is_running = false; |
| 717 | bool is_waiting_on_sync = false; | 676 | bool is_cancellable = false; |
| 718 | bool is_sync_cancelled = false; | 677 | bool is_sync_cancelled = false; |
| 719 | 678 | ||
| 720 | bool is_continuous_on_svc = false; | 679 | bool is_continuous_on_svc = false; |
| @@ -725,6 +684,8 @@ private: | |||
| 725 | 684 | ||
| 726 | bool was_running = false; | 685 | bool was_running = false; |
| 727 | 686 | ||
| 687 | bool signaled{}; | ||
| 688 | |||
| 728 | std::string name; | 689 | std::string name; |
| 729 | }; | 690 | }; |
| 730 | 691 | ||
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 4da69f503..2b91a89d1 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -139,9 +139,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { | |||
| 139 | server_port->AppendPendingSession(server); | 139 | server_port->AppendPendingSession(server); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | // Wake the threads waiting on the ServerPort | ||
| 143 | server_port->Signal(); | ||
| 144 | |||
| 145 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); | 142 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); |
| 146 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 143 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 147 | rb.Push(RESULT_SUCCESS); | 144 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 0925c10b4..8d91d600a 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -14,10 +14,10 @@ | |||
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/hle/kernel/handle_table.h" | 15 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/kernel/k_scheduler.h" | 16 | #include "core/hle/kernel/k_scheduler.h" |
| 17 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 17 | #include "core/hle/kernel/mutex.h" | 18 | #include "core/hle/kernel/mutex.h" |
| 18 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/kernel/readable_event.h" | 20 | #include "core/hle/kernel/readable_event.h" |
| 20 | #include "core/hle/kernel/synchronization_object.h" | ||
| 21 | #include "core/hle/kernel/thread.h" | 21 | #include "core/hle/kernel/thread.h" |
| 22 | #include "core/memory.h" | 22 | #include "core/memory.h" |
| 23 | 23 | ||
| @@ -169,7 +169,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons | |||
| 169 | return list; | 169 | return list; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& o) | 172 | WaitTreeSynchronizationObject::WaitTreeSynchronizationObject( |
| 173 | const Kernel::KSynchronizationObject& o) | ||
| 173 | : object(o) {} | 174 | : object(o) {} |
| 174 | WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; | 175 | WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; |
| 175 | 176 | ||
| @@ -188,7 +189,7 @@ QString WaitTreeSynchronizationObject::GetText() const { | |||
| 188 | } | 189 | } |
| 189 | 190 | ||
| 190 | std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make( | 191 | std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make( |
| 191 | const Kernel::SynchronizationObject& object) { | 192 | const Kernel::KSynchronizationObject& object) { |
| 192 | switch (object.GetHandleType()) { | 193 | switch (object.GetHandleType()) { |
| 193 | case Kernel::HandleType::ReadableEvent: | 194 | case Kernel::HandleType::ReadableEvent: |
| 194 | return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object)); | 195 | return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object)); |
| @@ -202,7 +203,7 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma | |||
| 202 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const { | 203 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const { |
| 203 | std::vector<std::unique_ptr<WaitTreeItem>> list; | 204 | std::vector<std::unique_ptr<WaitTreeItem>> list; |
| 204 | 205 | ||
| 205 | const auto& threads = object.GetWaitingThreads(); | 206 | const auto& threads = object.GetWaitingThreadsForDebugging(); |
| 206 | if (threads.empty()) { | 207 | if (threads.empty()) { |
| 207 | list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread"))); | 208 | list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread"))); |
| 208 | } else { | 209 | } else { |
| @@ -211,8 +212,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChi | |||
| 211 | return list; | 212 | return list; |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 214 | WaitTreeObjectList::WaitTreeObjectList( | 215 | WaitTreeObjectList::WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, |
| 215 | const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list, bool w_all) | 216 | bool w_all) |
| 216 | : object_list(list), wait_all(w_all) {} | 217 | : object_list(list), wait_all(w_all) {} |
| 217 | 218 | ||
| 218 | WaitTreeObjectList::~WaitTreeObjectList() = default; | 219 | WaitTreeObjectList::~WaitTreeObjectList() = default; |
| @@ -367,8 +368,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 367 | } | 368 | } |
| 368 | 369 | ||
| 369 | if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { | 370 | if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { |
| 370 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(), | 371 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(), |
| 371 | thread.IsWaitingSync())); | 372 | thread.IsCancellable())); |
| 372 | } | 373 | } |
| 373 | 374 | ||
| 374 | list.push_back(std::make_unique<WaitTreeCallstack>(thread)); | 375 | list.push_back(std::make_unique<WaitTreeCallstack>(thread)); |
| @@ -380,7 +381,7 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) | |||
| 380 | : WaitTreeSynchronizationObject(object) {} | 381 | : WaitTreeSynchronizationObject(object) {} |
| 381 | WaitTreeEvent::~WaitTreeEvent() = default; | 382 | WaitTreeEvent::~WaitTreeEvent() = default; |
| 382 | 383 | ||
| 383 | WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list) | 384 | WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list) |
| 384 | : thread_list(list) {} | 385 | : thread_list(list) {} |
| 385 | WaitTreeThreadList::~WaitTreeThreadList() = default; | 386 | WaitTreeThreadList::~WaitTreeThreadList() = default; |
| 386 | 387 | ||
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index 8e3bc4b24..cf96911ea 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h | |||
| @@ -18,8 +18,8 @@ class EmuThread; | |||
| 18 | 18 | ||
| 19 | namespace Kernel { | 19 | namespace Kernel { |
| 20 | class HandleTable; | 20 | class HandleTable; |
| 21 | class KSynchronizationObject; | ||
| 21 | class ReadableEvent; | 22 | class ReadableEvent; |
| 22 | class SynchronizationObject; | ||
| 23 | class Thread; | 23 | class Thread; |
| 24 | } // namespace Kernel | 24 | } // namespace Kernel |
| 25 | 25 | ||
| @@ -102,30 +102,29 @@ private: | |||
| 102 | class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { | 102 | class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { |
| 103 | Q_OBJECT | 103 | Q_OBJECT |
| 104 | public: | 104 | public: |
| 105 | explicit WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& object); | 105 | explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object); |
| 106 | ~WaitTreeSynchronizationObject() override; | 106 | ~WaitTreeSynchronizationObject() override; |
| 107 | 107 | ||
| 108 | static std::unique_ptr<WaitTreeSynchronizationObject> make( | 108 | static std::unique_ptr<WaitTreeSynchronizationObject> make( |
| 109 | const Kernel::SynchronizationObject& object); | 109 | const Kernel::KSynchronizationObject& object); |
| 110 | QString GetText() const override; | 110 | QString GetText() const override; |
| 111 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 111 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 112 | 112 | ||
| 113 | protected: | 113 | protected: |
| 114 | const Kernel::SynchronizationObject& object; | 114 | const Kernel::KSynchronizationObject& object; |
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | class WaitTreeObjectList : public WaitTreeExpandableItem { | 117 | class WaitTreeObjectList : public WaitTreeExpandableItem { |
| 118 | Q_OBJECT | 118 | Q_OBJECT |
| 119 | public: | 119 | public: |
| 120 | WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list, | 120 | WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, bool wait_all); |
| 121 | bool wait_all); | ||
| 122 | ~WaitTreeObjectList() override; | 121 | ~WaitTreeObjectList() override; |
| 123 | 122 | ||
| 124 | QString GetText() const override; | 123 | QString GetText() const override; |
| 125 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 124 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 126 | 125 | ||
| 127 | private: | 126 | private: |
| 128 | const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& object_list; | 127 | const std::vector<Kernel::KSynchronizationObject*>& object_list; |
| 129 | bool wait_all; | 128 | bool wait_all; |
| 130 | }; | 129 | }; |
| 131 | 130 | ||
| @@ -150,14 +149,14 @@ public: | |||
| 150 | class WaitTreeThreadList : public WaitTreeExpandableItem { | 149 | class WaitTreeThreadList : public WaitTreeExpandableItem { |
| 151 | Q_OBJECT | 150 | Q_OBJECT |
| 152 | public: | 151 | public: |
| 153 | explicit WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list); | 152 | explicit WaitTreeThreadList(const std::vector<Kernel::Thread*>& list); |
| 154 | ~WaitTreeThreadList() override; | 153 | ~WaitTreeThreadList() override; |
| 155 | 154 | ||
| 156 | QString GetText() const override; | 155 | QString GetText() const override; |
| 157 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 156 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 158 | 157 | ||
| 159 | private: | 158 | private: |
| 160 | const std::vector<std::shared_ptr<Kernel::Thread>>& thread_list; | 159 | const std::vector<Kernel::Thread*>& thread_list; |
| 161 | }; | 160 | }; |
| 162 | 161 | ||
| 163 | class WaitTreeModel : public QAbstractItemModel { | 162 | class WaitTreeModel : public QAbstractItemModel { |