summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-01-17 02:03:44 -0500
committerGravatar bunnei2015-01-21 19:09:03 -0500
commit7faf2d8e06e705d1866fa0d7848ff43541a4b172 (patch)
tree7cca6433c6b06a1299af1193df2cedac7ad522c5 /src
parentEvent: Fixed some bugs and cleanup (Subv) (diff)
downloadyuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.gz
yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.xz
yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.zip
WaitSynchronizationN: Implement return values
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp8
-rw-r--r--src/core/hle/kernel/event.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp4
-rw-r--r--src/core/hle/kernel/kernel.h7
-rw-r--r--src/core/hle/kernel/mutex.cpp8
-rw-r--r--src/core/hle/kernel/semaphore.cpp6
-rw-r--r--src/core/hle/kernel/thread.cpp94
-rw-r--r--src/core/hle/kernel/thread.h58
-rw-r--r--src/core/hle/kernel/timer.cpp6
-rw-r--r--src/core/hle/svc.cpp77
10 files changed, 189 insertions, 83 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index ff1472066..520601455 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -52,13 +52,13 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
52 // Wait current thread (acquire the arbiter)... 52 // Wait current thread (acquire the arbiter)...
53 case ArbitrationType::WaitIfLessThan: 53 case ArbitrationType::WaitIfLessThan:
54 if ((s32)Memory::Read32(address) <= value) { 54 if ((s32)Memory::Read32(address) <= value) {
55 Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); 55 Kernel::WaitCurrentThread_ArbitrateAddress(object, address);
56 HLE::Reschedule(__func__); 56 HLE::Reschedule(__func__);
57 } 57 }
58 break; 58 break;
59 case ArbitrationType::WaitIfLessThanWithTimeout: 59 case ArbitrationType::WaitIfLessThanWithTimeout:
60 if ((s32)Memory::Read32(address) <= value) { 60 if ((s32)Memory::Read32(address) <= value) {
61 Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); 61 Kernel::WaitCurrentThread_ArbitrateAddress(object, address);
62 Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); 62 Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);
63 HLE::Reschedule(__func__); 63 HLE::Reschedule(__func__);
64 } 64 }
@@ -68,7 +68,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
68 s32 memory_value = Memory::Read32(address) - 1; 68 s32 memory_value = Memory::Read32(address) - 1;
69 Memory::Write32(address, memory_value); 69 Memory::Write32(address, memory_value);
70 if (memory_value <= value) { 70 if (memory_value <= value) {
71 Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); 71 Kernel::WaitCurrentThread_ArbitrateAddress(object, address);
72 HLE::Reschedule(__func__); 72 HLE::Reschedule(__func__);
73 } 73 }
74 break; 74 break;
@@ -78,7 +78,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
78 s32 memory_value = Memory::Read32(address) - 1; 78 s32 memory_value = Memory::Read32(address) - 1;
79 Memory::Write32(address, memory_value); 79 Memory::Write32(address, memory_value);
80 if (memory_value <= value) { 80 if (memory_value <= value) {
81 Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); 81 Kernel::WaitCurrentThread_ArbitrateAddress(object, address);
82 Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); 82 Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);
83 HLE::Reschedule(__func__); 83 HLE::Reschedule(__func__);
84 } 84 }
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 540199e03..4173a980b 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -28,11 +28,11 @@ public:
28 bool signaled; ///< Whether the event has already been signaled 28 bool signaled; ///< Whether the event has already been signaled
29 std::string name; ///< Name of event (optional) 29 std::string name; ///< Name of event (optional)
30 30
31 ResultVal<bool> WaitSynchronization() override { 31 ResultVal<bool> WaitSynchronization(unsigned index) override {
32 bool wait = !signaled; 32 bool wait = !signaled;
33 if (wait) { 33 if (wait) {
34 AddWaitingThread(GetCurrentThread()); 34 AddWaitingThread(GetCurrentThread());
35 Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); 35 Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this, index);
36 } 36 }
37 return MakeResult<bool>(wait); 37 return MakeResult<bool>(wait);
38 } 38 }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1dba85939..be3495412 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -30,13 +30,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
30 waiting_threads.erase(itr); 30 waiting_threads.erase(itr);
31} 31}
32 32
33Thread* WaitObject::ResumeNextThread() { 33Thread* WaitObject::ReleaseNextThread() {
34 if (waiting_threads.empty()) 34 if (waiting_threads.empty())
35 return nullptr; 35 return nullptr;
36 36
37 auto next_thread = waiting_threads.front(); 37 auto next_thread = waiting_threads.front();
38 38
39 next_thread->ResumeFromWait(); 39 next_thread->ReleaseFromWait(this);
40 waiting_threads.erase(waiting_threads.begin()); 40 waiting_threads.erase(waiting_threads.begin());
41 41
42 return next_thread.get(); 42 return next_thread.get();
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 53b3f9143..af4e2f443 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -66,9 +66,10 @@ public:
66 66
67 /** 67 /**
68 * Wait for kernel object to synchronize. 68 * Wait for kernel object to synchronize.
69 * @param index Index of wait object (only applies to WaitSynchronizationN)
69 * @return True if the current thread should wait as a result of the wait 70 * @return True if the current thread should wait as a result of the wait
70 */ 71 */
71 virtual ResultVal<bool> WaitSynchronization() { 72 virtual ResultVal<bool> WaitSynchronization(unsigned index=0) {
72 LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); 73 LOG_ERROR(Kernel, "(UNIMPLEMENTED)");
73 return UnimplementedFunction(ErrorModule::Kernel); 74 return UnimplementedFunction(ErrorModule::Kernel);
74 } 75 }
@@ -111,10 +112,10 @@ public:
111 void RemoveWaitingThread(Thread* thead); 112 void RemoveWaitingThread(Thread* thead);
112 113
113 /** 114 /**
114 * Resumes (and removes) the next thread waiting on this object 115 * Releases (and removes) the next thread waiting on this object
115 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting 116 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
116 */ 117 */
117 Thread* ResumeNextThread(); 118 Thread* ReleaseNextThread();
118 119
119 /// Releases all threads waiting on this object 120 /// Releases all threads waiting on this object
120 void ReleaseAllWaitingThreads(); 121 void ReleaseAllWaitingThreads();
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 35d829606..78063b8f1 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -26,7 +26,7 @@ public:
26 Handle lock_thread; ///< Handle to thread that currently has mutex 26 Handle lock_thread; ///< Handle to thread that currently has mutex
27 std::string name; ///< Name of mutex (optional) 27 std::string name; ///< Name of mutex (optional)
28 28
29 ResultVal<bool> WaitSynchronization() override; 29 ResultVal<bool> WaitSynchronization(unsigned index) override;
30}; 30};
31 31
32//////////////////////////////////////////////////////////////////////////////////////////////////// 32////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -50,7 +50,7 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl
50 */ 50 */
51void ResumeWaitingThread(Mutex* mutex) { 51void ResumeWaitingThread(Mutex* mutex) {
52 // Find the next waiting thread for the mutex... 52 // Find the next waiting thread for the mutex...
53 auto next_thread = mutex->ResumeNextThread(); 53 auto next_thread = mutex->ReleaseNextThread();
54 if (next_thread != nullptr) { 54 if (next_thread != nullptr) {
55 MutexAcquireLock(mutex, next_thread->GetHandle()); 55 MutexAcquireLock(mutex, next_thread->GetHandle());
56 } else { 56 } else {
@@ -155,11 +155,11 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {
155 return handle; 155 return handle;
156} 156}
157 157
158ResultVal<bool> Mutex::WaitSynchronization() { 158ResultVal<bool> Mutex::WaitSynchronization(unsigned index) {
159 bool wait = locked; 159 bool wait = locked;
160 if (locked) { 160 if (locked) {
161 AddWaitingThread(GetCurrentThread()); 161 AddWaitingThread(GetCurrentThread());
162 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); 162 Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index);
163 } else { 163 } else {
164 // Lock the mutex when the first thread accesses it 164 // Lock the mutex when the first thread accesses it
165 locked = true; 165 locked = true;
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index af2c465e4..288928441 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -32,11 +32,11 @@ public:
32 return available_count > 0; 32 return available_count > 0;
33 } 33 }
34 34
35 ResultVal<bool> WaitSynchronization() override { 35 ResultVal<bool> WaitSynchronization(unsigned index) override {
36 bool wait = !IsAvailable(); 36 bool wait = !IsAvailable();
37 37
38 if (wait) { 38 if (wait) {
39 Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); 39 Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index);
40 AddWaitingThread(GetCurrentThread()); 40 AddWaitingThread(GetCurrentThread());
41 } else { 41 } else {
42 --available_count; 42 --available_count;
@@ -82,7 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
82 82
83 // Notify some of the threads that the semaphore has been released 83 // Notify some of the threads that the semaphore has been released
84 // stop once the semaphore is full again or there are no more waiting threads 84 // stop once the semaphore is full again or there are no more waiting threads
85 while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) { 85 while (semaphore->IsAvailable() && semaphore->ReleaseNextThread() != nullptr) {
86 --semaphore->available_count; 86 --semaphore->available_count;
87 } 87 }
88 88
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 00b72477e..0c9ecc091 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -22,11 +22,11 @@
22 22
23namespace Kernel { 23namespace Kernel {
24 24
25ResultVal<bool> Thread::WaitSynchronization() { 25ResultVal<bool> Thread::WaitSynchronization(unsigned index) {
26 const bool wait = status != THREADSTATUS_DORMANT; 26 const bool wait = status != THREADSTATUS_DORMANT;
27 if (wait) { 27 if (wait) {
28 AddWaitingThread(GetCurrentThread()); 28 AddWaitingThread(GetCurrentThread());
29 WaitCurrentThread(WAITTYPE_THREADEND, this); 29 WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index);
30 } 30 }
31 31
32 return MakeResult<bool>(wait); 32 return MakeResult<bool>(wait);
@@ -92,11 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) {
92 92
93/// Check if a thread is blocking on a specified wait type with a specified handle 93/// Check if a thread is blocking on a specified wait type with a specified handle
94static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { 94static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) {
95 auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); 95 for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) {
96 if (itr == thread->wait_objects.end()) { 96 if (itr->first == wait_object)
97 return false; 97 return CheckWaitType(thread, type);
98 } 98 }
99 return CheckWaitType(thread, type); 99 return false;
100} 100}
101 101
102/// Check if a thread is blocking on a specified wait type with a specified handle and address 102/// Check if a thread is blocking on a specified wait type with a specified handle and address
@@ -111,7 +111,7 @@ void Thread::Stop(const char* reason) {
111 111
112 ChangeReadyState(this, false); 112 ChangeReadyState(this, false);
113 status = THREADSTATUS_DORMANT; 113 status = THREADSTATUS_DORMANT;
114 ResumeAllWaitingThreads(); 114 ReleaseAllWaitingThreads();
115 115
116 // Stopped threads are never waiting. 116 // Stopped threads are never waiting.
117 wait_type = WAITTYPE_NONE; 117 wait_type = WAITTYPE_NONE;
@@ -135,7 +135,7 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) {
135} 135}
136 136
137/// Arbitrate the highest priority thread that is waiting 137/// Arbitrate the highest priority thread that is waiting
138Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { 138Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) {
139 Thread* highest_priority_thread = nullptr; 139 Thread* highest_priority_thread = nullptr;
140 s32 priority = THREADPRIO_LOWEST; 140 s32 priority = THREADPRIO_LOWEST;
141 141
@@ -155,19 +155,19 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) {
155 155
156 // If a thread was arbitrated, resume it 156 // If a thread was arbitrated, resume it
157 if (nullptr != highest_priority_thread) { 157 if (nullptr != highest_priority_thread) {
158 highest_priority_thread->ResumeFromWait(); 158 highest_priority_thread->ReleaseFromWait(arbiter);
159 } 159 }
160 160
161 return highest_priority_thread; 161 return highest_priority_thread;
162} 162}
163 163
164/// Arbitrate all threads currently waiting 164/// Arbitrate all threads currently waiting
165void ArbitrateAllThreads(Object* arbiter, u32 address) { 165void ArbitrateAllThreads(WaitObject* arbiter, u32 address) {
166 166
167 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 167 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
168 for (auto& thread : thread_list) { 168 for (auto& thread : thread_list) {
169 if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) 169 if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address))
170 thread->ResumeFromWait(); 170 thread->ReleaseFromWait(arbiter);
171 } 171 }
172} 172}
173 173
@@ -220,19 +220,32 @@ static Thread* NextThread() {
220 return next; 220 return next;
221} 221}
222 222
223void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { 223void WaitCurrentThread(WaitType wait_type) {
224 Thread* thread = GetCurrentThread();
225 thread->wait_type = wait_type;
226 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
227}
228
229void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index) {
224 Thread* thread = GetCurrentThread(); 230 Thread* thread = GetCurrentThread();
225 thread->wait_type = wait_type; 231 thread->wait_type = wait_type;
226 232
227 auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); 233 bool insert_wait_object = true;
228 if (res == thread->wait_objects.end()) { 234 for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) {
229 thread->wait_objects.push_back(wait_object); 235 if (itr->first == wait_object) {
236 insert_wait_object = false;
237 break;
238 }
230 } 239 }
240
241 if (insert_wait_object)
242 thread->wait_objects.push_back(std::pair<SharedPtr<WaitObject>, unsigned>(wait_object, index));
243
231 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); 244 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
232} 245}
233 246
234void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { 247void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) {
235 WaitCurrentThread(wait_type, wait_object); 248 WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0);
236 GetCurrentThread()->wait_address = wait_address; 249 GetCurrentThread()->wait_address = wait_address;
237} 250}
238 251
@@ -248,6 +261,9 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
248 return; 261 return;
249 } 262 }
250 263
264 thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
265 ErrorSummary::StatusChanged, ErrorLevel::Info), -1);
266
251 thread->ResumeFromWait(); 267 thread->ResumeFromWait();
252} 268}
253 269
@@ -262,7 +278,40 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) {
262 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); 278 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle());
263} 279}
264 280
265/// Resumes a thread from waiting by marking it as "ready" 281void Thread::ReleaseFromWait(WaitObject* wait_object) {
282 if (wait_objects.empty()) {
283 LOG_CRITICAL(Kernel, "thread is not waiting on any objects!");
284 return;
285 }
286
287 // Remove this thread from the wait_object
288 wait_object->RemoveWaitingThread(this);
289
290 // Find the waiting object
291 auto itr = wait_objects.begin();
292 for (; itr != wait_objects.end(); ++itr) {
293 if (wait_object == itr->first)
294 break;
295 }
296 unsigned index = itr->second;
297
298 // Remove the wait_object from this thread
299 if (itr != wait_objects.end())
300 wait_objects.erase(itr);
301
302 // If wait_all=false, resume the thread on a release wait_object from wait
303 if (!wait_all) {
304 SetReturnValue(RESULT_SUCCESS, index);
305 ResumeFromWait();
306 } else {
307 // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released
308 if (wait_objects.empty()) {
309 SetReturnValue(RESULT_SUCCESS, -1);
310 ResumeFromWait();
311 }
312 }
313}
314
266void Thread::ResumeFromWait() { 315void Thread::ResumeFromWait() {
267 // Cancel any outstanding wakeup events 316 // Cancel any outstanding wakeup events
268 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); 317 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle());
@@ -271,11 +320,12 @@ void Thread::ResumeFromWait() {
271 320
272 // Remove this thread from all other WaitObjects 321 // Remove this thread from all other WaitObjects
273 for (auto wait_object : wait_objects) 322 for (auto wait_object : wait_objects)
274 wait_object->RemoveWaitingThread(this); 323 wait_object.first->RemoveWaitingThread(this);
275 324
276 wait_objects.clear(); 325 wait_objects.clear();
277 326
278 wait_type = WAITTYPE_NONE; 327 wait_type = WAITTYPE_NONE;
328 wait_all = false;
279 if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 329 if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
280 ChangeReadyState(this, true); 330 ChangeReadyState(this, true);
281 } 331 }
@@ -342,6 +392,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
342 thread->initial_priority = thread->current_priority = priority; 392 thread->initial_priority = thread->current_priority = priority;
343 thread->processor_id = processor_id; 393 thread->processor_id = processor_id;
344 thread->wait_type = WAITTYPE_NONE; 394 thread->wait_type = WAITTYPE_NONE;
395 thread->wait_all = false;
345 thread->wait_objects.clear(); 396 thread->wait_objects.clear();
346 thread->wait_address = 0; 397 thread->wait_address = 0;
347 thread->name = std::move(name); 398 thread->name = std::move(name);
@@ -432,6 +483,11 @@ void Reschedule() {
432 } 483 }
433} 484}
434 485
486void Thread::SetReturnValue(ResultCode return_val, s32 out_val) {
487 context.cpu_registers[0] = return_val.raw;
488 context.cpu_registers[1] = out_val;
489}
490
435//////////////////////////////////////////////////////////////////////////////////////////////////// 491////////////////////////////////////////////////////////////////////////////////////////////////////
436 492
437void ThreadingInit() { 493void ThreadingInit() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 9ec96c18c..f3dc4eec0 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -70,7 +70,7 @@ public:
70 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } 70 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
71 inline bool IsIdle() const { return idle; } 71 inline bool IsIdle() const { return idle; }
72 72
73 ResultVal<bool> WaitSynchronization() override; 73 ResultVal<bool> WaitSynchronization(unsigned index) override;
74 74
75 s32 GetPriority() const { return current_priority; } 75 s32 GetPriority() const { return current_priority; }
76 void SetPriority(s32 priority); 76 void SetPriority(s32 priority);
@@ -78,9 +78,29 @@ public:
78 u32 GetThreadId() const { return thread_id; } 78 u32 GetThreadId() const { return thread_id; }
79 79
80 void Stop(const char* reason); 80 void Stop(const char* reason);
81 /// Resumes a thread from waiting by marking it as "ready". 81
82 /**
83 * Release an object from the thread's wait list
84 * @param wait_object WaitObject to release from the thread's wait list
85 */
86 void ReleaseFromWait(WaitObject* wait_object);
87
88 /// Resumes a thread from waiting by marking it as "ready"
82 void ResumeFromWait(); 89 void ResumeFromWait();
83 90
91 /**
92 * Sets the waiting mode of the thread
93 * @param wait_all If true, wait for all objects, otherwise just wait for the first one
94 */
95 void SetWaitAll(bool wait_all) { this->wait_all = wait_all; }
96
97 /**
98 * Sets the output values after the thread awakens from WaitSynchronization
99 * @param return_val Value returned
100 * @param out_val Value to set to the output parameter
101 */
102 void SetReturnValue(ResultCode return_val, s32 out_val);
103
84 Core::ThreadContext context; 104 Core::ThreadContext context;
85 105
86 u32 thread_id; 106 u32 thread_id;
@@ -96,7 +116,7 @@ public:
96 s32 processor_id; 116 s32 processor_id;
97 117
98 WaitType wait_type; 118 WaitType wait_type;
99 std::vector<SharedPtr<WaitObject>> wait_objects; 119 std::vector<std::pair<SharedPtr<WaitObject>, unsigned>> wait_objects;
100 VAddr wait_address; 120 VAddr wait_address;
101 121
102 std::string name; 122 std::string name;
@@ -105,6 +125,8 @@ public:
105 bool idle = false; 125 bool idle = false;
106 126
107private: 127private:
128 bool wait_all = false;
129
108 Thread() = default; 130 Thread() = default;
109}; 131};
110 132
@@ -115,37 +137,41 @@ SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size);
115void Reschedule(); 137void Reschedule();
116 138
117/// Arbitrate the highest priority thread that is waiting 139/// Arbitrate the highest priority thread that is waiting
118Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); 140Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address);
119 141
120/// Arbitrate all threads currently waiting... 142/// Arbitrate all threads currently waiting...
121void ArbitrateAllThreads(Object* arbiter, u32 address); 143void ArbitrateAllThreads(WaitObject* arbiter, u32 address);
122 144
123/// Gets the current thread 145/// Gets the current thread
124Thread* GetCurrentThread(); 146Thread* GetCurrentThread();
125 147
126/** 148/**
127 * Puts the current thread in the wait state for the given type 149 * Waits the current thread for the given type
128 * @param wait_type Type of wait 150 * @param wait_type Type of wait
129 * @param wait_object Kernel object that we are waiting on, defaults to current thread
130 */ 151 */
131void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object = GetCurrentThread()); 152void WaitCurrentThread(WaitType wait_type);
132 153
133/** 154/**
134 * Schedules an event to wake up the specified thread after the specified delay. 155 * Waits the current thread from a WaitSynchronization call
135 * @param thread The thread to wake after the delay. 156 * @param wait_type Type of wait
136 * @param nanoseconds The time this thread will be allowed to sleep for. 157 * @param wait_object Kernel object that we are waiting on
158 * @param index Index of calling object (for WaitSynchronizationN only)
137 */ 159 */
138void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); 160void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index=0);
139 161
140/** 162/**
141 * Puts the current thread in the wait state for the given type 163 * Waits the current thread from an ArbitrateAddress call
142 * @param wait_type Type of wait
143 * @param wait_object Kernel object that we are waiting on 164 * @param wait_object Kernel object that we are waiting on
144 * @param wait_address Arbitration address used to resume from wait 165 * @param wait_address Arbitration address used to resume from wait
145 */ 166 */
146void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address); 167void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address);
147
148 168
169/**
170 * Schedules an event to wake up the specified thread after the specified delay.
171 * @param handle The thread handle.
172 * @param nanoseconds The time this thread will be allowed to sleep for.
173 */
174void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds);
149 175
150/** 176/**
151 * Sets up the idle thread, this is a thread that is intended to never execute instructions, 177 * Sets up the idle thread, this is a thread that is intended to never execute instructions,
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 2d4fa4c01..c97ae6c5c 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -29,11 +29,11 @@ public:
29 u64 initial_delay; ///< The delay until the timer fires for the first time 29 u64 initial_delay; ///< The delay until the timer fires for the first time
30 u64 interval_delay; ///< The delay until the timer fires after the first time 30 u64 interval_delay; ///< The delay until the timer fires after the first time
31 31
32 ResultVal<bool> WaitSynchronization() override { 32 ResultVal<bool> WaitSynchronization(unsigned index) override {
33 bool wait = !signaled; 33 bool wait = !signaled;
34 if (wait) { 34 if (wait) {
35 AddWaitingThread(GetCurrentThread()); 35 AddWaitingThread(GetCurrentThread());
36 Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); 36 Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this, index);
37 } 37 }
38 return MakeResult<bool>(wait); 38 return MakeResult<bool>(wait);
39 } 39 }
@@ -91,7 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
91 timer->signaled = true; 91 timer->signaled = true;
92 92
93 // Resume all waiting threads 93 // Resume all waiting threads
94 timer->ResumeAllWaitingThreads(); 94 timer->ReleaseAllWaitingThreads();
95 95
96 if (timer->reset_type == RESETTYPE_ONESHOT) 96 if (timer->reset_type == RESETTYPE_ONESHOT)
97 timer->signaled = false; 97 timer->signaled = false;
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index a487f757c..170ac87f3 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -133,6 +133,9 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
133 if (wait.Succeeded() && *wait) { 133 if (wait.Succeeded() && *wait) {
134 // Create an event to wake the thread up after the specified nanosecond delay has passed 134 // Create an event to wake the thread up after the specified nanosecond delay has passed
135 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); 135 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
136
137 Kernel::GetCurrentThread()->SetWaitAll(false);
138
136 HLE::Reschedule(__func__); 139 HLE::Reschedule(__func__);
137 } 140 }
138 141
@@ -140,44 +143,64 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
140} 143}
141 144
142/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 145/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
143static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, 146static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
144 s64 nano_seconds) { 147 bool wait_thread = false;
145 148 bool wait_all_succeeded = false;
146 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 149 int handle_index = 0;
147 bool unlock_all = true;
148 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
149 150
150 LOG_TRACE(Kernel_SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", 151 while (handle_index < handle_count) {
151 handle_count, (wait_all ? "true" : "false"), nano_seconds); 152 SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[handle_index]);
152
153 // Iterate through each handle, synchronize kernel object
154 for (s32 i = 0; i < handle_count; i++) {
155 SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]);
156 if (object == nullptr) 153 if (object == nullptr)
157 return InvalidHandle(ErrorModule::Kernel).raw; 154 return InvalidHandle(ErrorModule::Kernel).raw;
158 155
159 LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], 156 ResultVal<bool> wait = object->WaitSynchronization(handle_index);
160 object->GetTypeName().c_str(), object->GetName().c_str());
161 157
162 // TODO(yuriks): Verify how the real function behaves when an error happens here 158 wait_thread = (wait.Succeeded() && *wait);
163 ResultVal<bool> wait_result = object->WaitSynchronization();
164 bool wait = wait_result.Succeeded() && *wait_result;
165 159
166 if (!wait && !wait_all) { 160 // If this object waited and we are waiting on all objects to synchronize
167 *out = i; 161 if (wait_thread && wait_all) {
168 return RESULT_SUCCESS.raw; 162 // Enforce later on that this thread does not continue
169 } else { 163 wait_all_succeeded = true;
170 unlock_all = false;
171 } 164 }
165
166 // If this object synchronized and we are not waiting on all objects to synchronize
167 if (!wait_thread && !wait_all)
168 // We're done, the thread will continue
169 break;
170
171 handle_index++;
172 }
173
174 // Change the thread state to waiting if blocking on all handles...
175 if (wait_thread || wait_all_succeeded) {
176 // Create an event to wake the thread up after the specified nanosecond delay has passed
177 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
178 Kernel::GetCurrentThread()->SetWaitAll(wait_all);
179
180 HLE::Reschedule(__func__);
181
182 // NOTE: output of this SVC will be set later depending on how the thread resumes
183 return RESULT_DUMMY.raw;
172 } 184 }
173 185
174 if (wait_all && unlock_all) { 186 // Acquire objects if we did not wait...
175 *out = handle_count; 187 for (int i = 0; i < handle_count; ++i) {
176 return RESULT_SUCCESS.raw; 188 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
189
190 // Acquire the object if it is not waiting...
191 if (!object->ShouldWait()) {
192 object->Acquire();
193
194 // If this was the first non-waiting object and 'wait_all' is false, don't acquire
195 // any other objects
196 if (!wait_all)
197 break;
198 }
177 } 199 }
178 200
179 // Check for next thread to schedule 201 // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
180 HLE::Reschedule(__func__); 202 // not seem to set it to any meaningful value.
203 *out = wait_all ? 0 : handle_index;
181 204
182 return RESULT_SUCCESS.raw; 205 return RESULT_SUCCESS.raw;
183} 206}