summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/thread.cpp53
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/svc.cpp3
3 files changed, 35 insertions, 22 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 47be22653..834308926 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -147,16 +147,19 @@ void ChangeReadyState(Thread* t, bool ready) {
147 } 147 }
148} 148}
149 149
150/// Verify that a thread has not been released from waiting 150/// Check if a thread is blocking on a specified wait type
151static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { 151static bool CheckWaitType(const Thread* thread, WaitType type) {
152 _dbg_assert_(Kernel, thread != nullptr); 152 return (type == thread->wait_type) && (thread->IsWaiting());
153 return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
154} 153}
155 154
156/// Verify that a thread has not been released from waiting (with wait address) 155/// Check if a thread is blocking on a specified wait type with a specified handle
157static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { 156static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) {
158 _dbg_assert_(Kernel, thread != nullptr); 157 return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle);
159 return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address); 158}
159
160/// Check if a thread is blocking on a specified wait type with a specified handle and address
161static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
162 return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address);
160} 163}
161 164
162/// Stops the current thread 165/// Stops the current thread
@@ -171,9 +174,9 @@ ResultCode StopThread(Handle handle, const char* reason) {
171 thread->status = THREADSTATUS_DORMANT; 174 thread->status = THREADSTATUS_DORMANT;
172 for (Handle waiting_handle : thread->waiting_threads) { 175 for (Handle waiting_handle : thread->waiting_threads) {
173 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); 176 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
174 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { 177
178 if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle))
175 ResumeThreadFromWait(waiting_handle); 179 ResumeThreadFromWait(waiting_handle);
176 }
177 } 180 }
178 thread->waiting_threads.clear(); 181 thread->waiting_threads.clear();
179 182
@@ -209,7 +212,7 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
209 for (Handle handle : thread_queue) { 212 for (Handle handle : thread_queue) {
210 Thread* thread = g_object_pool.Get<Thread>(handle); 213 Thread* thread = g_object_pool.Get<Thread>(handle);
211 214
212 if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) 215 if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
213 continue; 216 continue;
214 217
215 if (thread == nullptr) 218 if (thread == nullptr)
@@ -234,7 +237,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) {
234 for (Handle handle : thread_queue) { 237 for (Handle handle : thread_queue) {
235 Thread* thread = g_object_pool.Get<Thread>(handle); 238 Thread* thread = g_object_pool.Get<Thread>(handle);
236 239
237 if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) 240 if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
238 ResumeThreadFromWait(handle); 241 ResumeThreadFromWait(handle);
239 } 242 }
240} 243}
@@ -305,6 +308,8 @@ void ResumeThreadFromWait(Handle handle) {
305 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); 308 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
306 if (thread) { 309 if (thread) {
307 thread->status &= ~THREADSTATUS_WAIT; 310 thread->status &= ~THREADSTATUS_WAIT;
311 thread->wait_handle = 0;
312 thread->wait_type = WAITTYPE_NONE;
308 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 313 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
309 ChangeReadyState(thread, true); 314 ChangeReadyState(thread, true);
310 } 315 }
@@ -468,19 +473,27 @@ void Reschedule() {
468 Thread* prev = GetCurrentThread(); 473 Thread* prev = GetCurrentThread();
469 Thread* next = NextThread(); 474 Thread* next = NextThread();
470 HLE::g_reschedule = false; 475 HLE::g_reschedule = false;
471 if (next > 0) {
472 LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
473 476
477 if (next != nullptr) {
478 LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
474 SwitchContext(next); 479 SwitchContext(next);
480 } else {
481 LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
475 482
476 // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep 483 for (Handle handle : thread_queue) {
477 // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. 484 Thread* thread = g_object_pool.Get<Thread>(handle);
478 // This results in the current thread yielding on a VBLANK once, and then it will be 485 LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X",
479 // immediately placed back in the queue for execution. 486 thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle);
480 if (prev->wait_type == WAITTYPE_VBLANK) {
481 ResumeThreadFromWait(prev->GetHandle());
482 } 487 }
483 } 488 }
489
490 // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put
491 // to sleep. So, we'll just immediately set it to "ready" again after an attempted context
492 // switch has occurred. This results in the current thread yielding on a sleep once, and then it
493 // will immediately be placed back in the queue for execution.
494
495 if (CheckWaitType(prev, WAITTYPE_SLEEP))
496 ResumeThreadFromWait(prev->GetHandle());
484} 497}
485 498
486ResultCode GetThreadId(u32* thread_id, Handle handle) { 499ResultCode GetThreadId(u32* thread_id, Handle handle) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index ec3b887d4..65e8ef554 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -40,7 +40,6 @@ enum WaitType {
40 WAITTYPE_SEMA, 40 WAITTYPE_SEMA,
41 WAITTYPE_EVENT, 41 WAITTYPE_EVENT,
42 WAITTYPE_THREADEND, 42 WAITTYPE_THREADEND,
43 WAITTYPE_VBLANK,
44 WAITTYPE_MUTEX, 43 WAITTYPE_MUTEX,
45 WAITTYPE_SYNCH, 44 WAITTYPE_SYNCH,
46 WAITTYPE_ARB, 45 WAITTYPE_ARB,
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 47e9bf77e..70ef7839c 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -352,7 +352,8 @@ static Result ClearEvent(Handle evt) {
352static void SleepThread(s64 nanoseconds) { 352static void SleepThread(s64 nanoseconds) {
353 LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); 353 LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
354 354
355 // Check for next thread to schedule 355 // Sleep current thread and check for next thread to schedule
356 Kernel::WaitCurrentThread(WAITTYPE_SLEEP);
356 HLE::Reschedule(__func__); 357 HLE::Reschedule(__func__);
357} 358}
358 359