summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp10
-rw-r--r--src/core/hle/kernel/client_port.cpp3
-rw-r--r--src/core/hle/kernel/client_session.cpp11
-rw-r--r--src/core/hle/kernel/client_session.h8
-rw-r--r--src/core/hle/kernel/errors.h3
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp5
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp171
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h58
-rw-r--r--src/core/hle/kernel/kernel.cpp15
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/mutex.cpp4
-rw-r--r--src/core/hle/kernel/process.cpp21
-rw-r--r--src/core/hle/kernel/process.h14
-rw-r--r--src/core/hle/kernel/readable_event.cpp18
-rw-r--r--src/core/hle/kernel/readable_event.h12
-rw-r--r--src/core/hle/kernel/server_port.cpp14
-rw-r--r--src/core/hle/kernel/server_port.h7
-rw-r--r--src/core/hle/kernel/server_session.cpp23
-rw-r--r--src/core/hle/kernel/server_session.h12
-rw-r--r--src/core/hle/kernel/session.cpp11
-rw-r--r--src/core/hle/kernel/session.h8
-rw-r--r--src/core/hle/kernel/svc.cpp47
-rw-r--r--src/core/hle/kernel/svc_wrap.h9
-rw-r--r--src/core/hle/kernel/synchronization.cpp116
-rw-r--r--src/core/hle/kernel/synchronization.h44
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp49
-rw-r--r--src/core/hle/kernel/synchronization_object.h77
-rw-r--r--src/core/hle/kernel/thread.cpp66
-rw-r--r--src/core/hle/kernel/thread.h131
-rw-r--r--src/core/hle/service/sm/sm.cpp3
-rw-r--r--src/yuzu/debugger/wait_tree.cpp19
-rw-r--r--src/yuzu/debugger/wait_tree.h17
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
13namespace Kernel { 13namespace Kernel {
14 14
15ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {} 15ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
16 16
17ClientSession::~ClientSession() { 17ClientSession::~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
25bool ClientSession::ShouldWait(const Thread* thread) const {
26 UNIMPLEMENTED();
27 return {};
28}
29
30void ClientSession::Acquire(Thread* thread) {
31 UNIMPLEMENTED();
32}
33
34bool ClientSession::IsSignaled() const { 25bool 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
13union ResultCode; 13union ResultCode;
@@ -26,7 +26,7 @@ class KernelCore;
26class Session; 26class Session;
27class Thread; 27class Thread;
28 28
29class ClientSession final : public SynchronizationObject { 29class ClientSession final : public KSynchronizationObject {
30public: 30public:
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
58private: 54private:
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 {
13constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; 13constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
14constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; 14constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
15constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59}; 15constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59};
16constexpr ResultCode ERR_TERMINATION_REQUESTED{ErrorModule::Kernel, 59};
16constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; 17constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
17constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; 18constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
18constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103}; 19constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103};
19constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104}; 20constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};
20constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; 21constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
21constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106}; 22constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
23constexpr ResultCode ERR_INVALID_CURRENT_MEMORY{ErrorModule::Kernel, 106};
22constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; 24constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
23constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110}; 25constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
24constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113}; 26constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
@@ -28,6 +30,7 @@ constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
28constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116}; 30constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
29constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117}; 31constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
30constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118}; 32constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
33constexpr ResultCode ERR_CANCELLED{ErrorModule::Kernel, 118};
31constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119}; 34constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
32constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120}; 35constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
33constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121}; 36constexpr 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
646void KScheduler::Reload(Thread* thread) { 646void 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
14namespace Kernel {
15
16ResultCode 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
136KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {}
137
138KSynchronizationObject ::~KSynchronizationObject() = default;
139
140void 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
158std::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
12namespace Kernel {
13
14class KernelCore;
15class Synchronization;
16class Thread;
17
18/// Class that represents a Kernel object that a thread can be waiting on
19class KSynchronizationObject : public Object {
20public:
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
34protected:
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
43private:
44 ThreadListNode* thread_list_head{};
45 ThreadListNode* thread_list_tail{};
46};
47
48// Specialization of DynamicObjectCast for KSynchronizationObjects
49template <>
50inline 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
52struct KernelCore::Impl { 51struct 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
464Kernel::Synchronization& KernelCore::Synchronization() {
465 return impl->synchronization;
466}
467
468const Kernel::Synchronization& KernelCore::Synchronization() const {
469 return impl->synchronization;
470}
471
472Kernel::TimeManager& KernelCore::TimeManager() { 461Kernel::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
409bool Process::IsSignaled() const {
410 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
411 return is_signaled;
412}
413
409Process::Process(Core::System& system) 414Process::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
414Process::~Process() = default; 419Process::~Process() = default;
415 420
416void Process::Acquire(Thread* thread) {
417 ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
418}
419
420bool Process::ShouldWait(const Thread* thread) const {
421 return !is_signaled;
422}
423
424void Process::ChangeStatus(ProcessStatus new_status) { 421void 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
434ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { 431ResultCode 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
21namespace Core { 21namespace Core {
@@ -63,7 +63,7 @@ enum class ProcessStatus {
63 DebugBreak, 63 DebugBreak,
64}; 64};
65 65
66class Process final : public SynchronizationObject { 66class Process final : public KSynchronizationObject {
67public: 67public:
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
316private: 318private:
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
15namespace Kernel { 15namespace Kernel {
16 16
17ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {} 17ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {}
18ReadableEvent::~ReadableEvent() = default; 18ReadableEvent::~ReadableEvent() = default;
19 19
20bool ReadableEvent::ShouldWait(const Thread* thread) const {
21 return !is_signaled;
22}
23
24void ReadableEvent::Acquire(Thread* thread) {
25 ASSERT_MSG(IsSignaled(), "object unavailable!");
26}
27
28void ReadableEvent::Signal() { 20void 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
29bool ReadableEvent::IsSignaled() const {
30 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
31
32 return is_signaled;
35} 33}
36 34
37void ReadableEvent::Clear() { 35void 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
10union ResultCode; 10union ResultCode;
11 11
@@ -14,7 +14,7 @@ namespace Kernel {
14class KernelCore; 14class KernelCore;
15class WritableEvent; 15class WritableEvent;
16 16
17class ReadableEvent final : public SynchronizationObject { 17class ReadableEvent final : public KSynchronizationObject {
18 friend class WritableEvent; 18 friend class WritableEvent;
19 19
20public: 20public:
@@ -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
51private: 50private:
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
14namespace Kernel { 14namespace Kernel {
15 15
16ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {} 16ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
17ServerPort::~ServerPort() = default; 17ServerPort::~ServerPort() = default;
18 18
19ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { 19ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
@@ -28,15 +28,9 @@ ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
28 28
29void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { 29void 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();
33bool 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
38void ServerPort::Acquire(Thread* thread) {
39 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
40} 34}
41 35
42bool ServerPort::IsSignaled() const { 36bool 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
16namespace Kernel { 16namespace Kernel {
@@ -20,7 +20,7 @@ class KernelCore;
20class ServerSession; 20class ServerSession;
21class SessionRequestHandler; 21class SessionRequestHandler;
22 22
23class ServerPort final : public SynchronizationObject { 23class ServerPort final : public KSynchronizationObject {
24public: 24public:
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
87private: 84private:
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
25namespace Kernel { 25namespace Kernel {
26 26
27ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} 27ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
28 28
29ServerSession::~ServerSession() { 29ServerSession::~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
45bool 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
55bool ServerSession::IsSignaled() const { 45bool 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
65void 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
74void ServerSession::ClientDisconnected() { 55void 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
17namespace Core::Memory { 17namespace 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 */
46class ServerSession final : public SynchronizationObject { 46class ServerSession final : public KSynchronizationObject {
47 friend class ServiceThread; 47 friend class ServiceThread;
48 48
49public: 49public:
@@ -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
133private: 129private:
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
10namespace Kernel { 10namespace Kernel {
11 11
12Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {} 12Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
13Session::~Session() = default; 13Session::~Session() = default;
14 14
15Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { 15Session::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
27bool Session::ShouldWait(const Thread* thread) const {
28 UNIMPLEMENTED();
29 return {};
30}
31
32bool Session::IsSignaled() const { 27bool Session::IsSignaled() const {
33 UNIMPLEMENTED(); 28 UNIMPLEMENTED();
34 return true; 29 return true;
35} 30}
36 31
37void 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
13namespace Kernel { 13namespace 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 */
22class Session final : public SynchronizationObject { 22class Session final : public KSynchronizationObject {
23public: 23public:
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
439static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, 428static 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
481static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, 468static 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
218template <ResultCode func(Core::System&, u32*, u64, u64, s64)> 218// Used by WaitSynchronization
219template <ResultCode func(Core::System&, s32*, u64, u64, s64)>
219void SvcWrap64(Core::System& system) { 220void SvcWrap64(Core::System& system) {
220 u32 param_1 = 0; 221 s32 param_1 = 0;
221 const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)), 222 const u32 retval = func(system, &param_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
542template <ResultCode func(Core::System&, u32, u32, s32, u32, Handle*)> 543template <ResultCode func(Core::System&, u32, u32, s32, u32, s32*)>
543void SvcWrap32(Core::System& system) { 544void 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), &param_1) 547 Param32(system, 3), &param_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
16namespace Kernel {
17
18Synchronization::Synchronization(Core::System& system) : system{system} {}
19
20void 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
38std::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
14namespace Core {
15class System;
16} // namespace Core
17
18namespace Kernel {
19
20class 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 */
27class Synchronization {
28public:
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
41private:
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
17namespace Kernel {
18
19SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
20SynchronizationObject::~SynchronizationObject() = default;
21
22void SynchronizationObject::Signal() {
23 kernel.Synchronization().SignalObject(*this);
24}
25
26void 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
32void 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
41void SynchronizationObject::ClearWaitingThreads() {
42 waiting_threads.clear();
43}
44
45const 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
13namespace Kernel {
14
15class KernelCore;
16class Synchronization;
17class Thread;
18
19/// Class that represents a Kernel object that a thread can be waiting on
20class SynchronizationObject : public Object {
21public:
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
59protected:
60 std::atomic_bool is_signaled{}; // Tells if this sync object is signaled
61
62private:
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
68template <>
69inline 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
35namespace Kernel { 35namespace Kernel {
36 36
37bool Thread::ShouldWait(const Thread* thread) const {
38 return status != ThreadStatus::Dead;
39}
40
41bool Thread::IsSignaled() const { 37bool Thread::IsSignaled() const {
42 return status == ThreadStatus::Dead; 38 return signaled;
43} 39}
44 40
45void Thread::Acquire(Thread* thread) { 41Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {}
46 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
47}
48
49Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {}
50Thread::~Thread() = default; 42Thread::~Thread() = default;
51 43
52void Thread::Stop() { 44void 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
70void Thread::ResumeFromWait() { 63void 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
102void Thread::OnWakeUp() { 92void Thread::OnWakeUp() {
103 KScopedSchedulerLock lock(kernel); 93 KScopedSchedulerLock lock(kernel);
104 SetStatus(ThreadStatus::Ready); 94 SetState(ThreadStatus::Ready);
105} 95}
106 96
107ResultCode Thread::Start() { 97ResultCode 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
113void Thread::CancelWait() { 103void 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
125static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, 115static 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
237void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { 227void 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
242s32 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
248VAddr Thread::GetCommandBufferAddress() const { 232VAddr 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
254void Thread::SetStatus(ThreadStatus new_status) { 238void 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
354bool 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
361bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) {
362 ASSERT(hle_callback);
363 return hle_callback(std::move(thread));
364}
365
366ResultCode Thread::SetActivity(ThreadActivity value) { 338ResultCode 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) {
407void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { 379void 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) {
415void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { 387void 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
21namespace Common { 21namespace Common {
@@ -117,7 +117,7 @@ enum class ThreadSchedMasks : u32 {
117 ForcePauseMask = 0x0070, 117 ForcePauseMask = 0x0070,
118}; 118};
119 119
120class Thread final : public SynchronizationObject { 120class Thread final : public KSynchronizationObject {
121public: 121public:
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
625private: 588private:
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
172WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& o) 172WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(
173 const Kernel::KSynchronizationObject& o)
173 : object(o) {} 174 : object(o) {}
174WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; 175WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
175 176
@@ -188,7 +189,7 @@ QString WaitTreeSynchronizationObject::GetText() const {
188} 189}
189 190
190std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make( 191std::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
202std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const { 203std::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
214WaitTreeObjectList::WaitTreeObjectList( 215WaitTreeObjectList::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
218WaitTreeObjectList::~WaitTreeObjectList() = default; 219WaitTreeObjectList::~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) {}
381WaitTreeEvent::~WaitTreeEvent() = default; 382WaitTreeEvent::~WaitTreeEvent() = default;
382 383
383WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list) 384WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list)
384 : thread_list(list) {} 385 : thread_list(list) {}
385WaitTreeThreadList::~WaitTreeThreadList() = default; 386WaitTreeThreadList::~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
19namespace Kernel { 19namespace Kernel {
20class HandleTable; 20class HandleTable;
21class KSynchronizationObject;
21class ReadableEvent; 22class ReadableEvent;
22class SynchronizationObject;
23class Thread; 23class Thread;
24} // namespace Kernel 24} // namespace Kernel
25 25
@@ -102,30 +102,29 @@ private:
102class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { 102class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
103 Q_OBJECT 103 Q_OBJECT
104public: 104public:
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
113protected: 113protected:
114 const Kernel::SynchronizationObject& object; 114 const Kernel::KSynchronizationObject& object;
115}; 115};
116 116
117class WaitTreeObjectList : public WaitTreeExpandableItem { 117class WaitTreeObjectList : public WaitTreeExpandableItem {
118 Q_OBJECT 118 Q_OBJECT
119public: 119public:
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
127private: 126private:
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:
150class WaitTreeThreadList : public WaitTreeExpandableItem { 149class WaitTreeThreadList : public WaitTreeExpandableItem {
151 Q_OBJECT 150 Q_OBJECT
152public: 151public:
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
159private: 158private:
160 const std::vector<std::shared_ptr<Kernel::Thread>>& thread_list; 159 const std::vector<Kernel::Thread*>& thread_list;
161}; 160};
162 161
163class WaitTreeModel : public QAbstractItemModel { 162class WaitTreeModel : public QAbstractItemModel {