diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 53 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 1 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 3 |
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 |
| 151 | static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { | 151 | static 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 |
| 157 | static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | 156 | static 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 | ||
| 161 | static 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 | ||
| 486 | ResultCode GetThreadId(u32* thread_id, Handle handle) { | 499 | ResultCode 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) { | |||
| 352 | static void SleepThread(s64 nanoseconds) { | 352 | static 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 | ||