summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp94
1 files changed, 75 insertions, 19 deletions
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() {