diff options
| author | 2014-12-29 19:47:41 -0800 | |
|---|---|---|
| committer | 2014-12-29 19:47:41 -0800 | |
| commit | 8ba9ac0f74abb0408a26207a76a0c1808bad8de0 (patch) | |
| tree | f1c7c3393fa726435b5b90bf335567c93e528ef1 /src/core/hle/kernel/thread.cpp | |
| parent | Add comment regarding __WIN32__ in SkyEye code (diff) | |
| parent | Merge pull request #367 from bunnei/usat_ssat (diff) | |
| download | yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.tar.gz yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.tar.xz yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.zip | |
Fix merge conflicts
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 136 |
1 files changed, 90 insertions, 46 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f3f54a4e9..872df2d14 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project | 1 | // Copyright 2014 Citra Emulator Project / PPSSPP Project |
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "core/hle/hle.h" | 14 | #include "core/hle/hle.h" |
| 15 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 17 | #include "core/hle/kernel/mutex.h" | ||
| 17 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| 18 | #include "core/mem_map.h" | 19 | #include "core/mem_map.h" |
| 19 | 20 | ||
| @@ -25,8 +26,8 @@ public: | |||
| 25 | std::string GetName() const override { return name; } | 26 | std::string GetName() const override { return name; } |
| 26 | std::string GetTypeName() const override { return "Thread"; } | 27 | std::string GetTypeName() const override { return "Thread"; } |
| 27 | 28 | ||
| 28 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } | 29 | static const HandleType HANDLE_TYPE = HandleType::Thread; |
| 29 | Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; } | 30 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 30 | 31 | ||
| 31 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } | 32 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } |
| 32 | inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } | 33 | inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } |
| @@ -49,6 +50,8 @@ public: | |||
| 49 | 50 | ||
| 50 | ThreadContext context; | 51 | ThreadContext context; |
| 51 | 52 | ||
| 53 | u32 thread_id; | ||
| 54 | |||
| 52 | u32 status; | 55 | u32 status; |
| 53 | u32 entry_point; | 56 | u32 entry_point; |
| 54 | u32 stack_top; | 57 | u32 stack_top; |
| @@ -61,6 +64,7 @@ public: | |||
| 61 | 64 | ||
| 62 | WaitType wait_type; | 65 | WaitType wait_type; |
| 63 | Handle wait_handle; | 66 | Handle wait_handle; |
| 67 | VAddr wait_address; | ||
| 64 | 68 | ||
| 65 | std::vector<Handle> waiting_threads; | 69 | std::vector<Handle> waiting_threads; |
| 66 | 70 | ||
| @@ -76,8 +80,10 @@ static Common::ThreadQueueList<Handle> thread_ready_queue; | |||
| 76 | static Handle current_thread_handle; | 80 | static Handle current_thread_handle; |
| 77 | static Thread* current_thread; | 81 | static Thread* current_thread; |
| 78 | 82 | ||
| 79 | /// Gets the current thread | 83 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup |
| 80 | inline Thread* GetCurrentThread() { | 84 | static u32 next_thread_id; ///< The next available thread id |
| 85 | |||
| 86 | Thread* GetCurrentThread() { | ||
| 81 | return current_thread; | 87 | return current_thread; |
| 82 | } | 88 | } |
| 83 | 89 | ||
| @@ -121,6 +127,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | |||
| 121 | } | 127 | } |
| 122 | t->wait_type = WAITTYPE_NONE; | 128 | t->wait_type = WAITTYPE_NONE; |
| 123 | t->wait_handle = 0; | 129 | t->wait_handle = 0; |
| 130 | t->wait_address = 0; | ||
| 124 | } | 131 | } |
| 125 | 132 | ||
| 126 | /// Change a thread to "ready" state | 133 | /// Change a thread to "ready" state |
| @@ -140,30 +147,43 @@ void ChangeReadyState(Thread* t, bool ready) { | |||
| 140 | } | 147 | } |
| 141 | } | 148 | } |
| 142 | 149 | ||
| 143 | /// Verify that a thread has not been released from waiting | 150 | /// Check if a thread is blocking on a specified wait type |
| 144 | inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { | 151 | static bool CheckWaitType(const Thread* thread, WaitType type) { |
| 145 | _dbg_assert_(KERNEL, thread != nullptr); | 152 | return (type == thread->wait_type) && (thread->IsWaiting()); |
| 146 | return type == thread->wait_type && wait_handle == thread->wait_handle; | 153 | } |
| 154 | |||
| 155 | /// Check if a thread is blocking on a specified wait type with a specified handle | ||
| 156 | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) { | ||
| 157 | return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle); | ||
| 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); | ||
| 147 | } | 163 | } |
| 148 | 164 | ||
| 149 | /// Stops the current thread | 165 | /// Stops the current thread |
| 150 | ResultCode StopThread(Handle handle, const char* reason) { | 166 | ResultCode StopThread(Handle handle, const char* reason) { |
| 151 | Thread* thread = g_object_pool.Get<Thread>(handle); | 167 | Thread* thread = g_handle_table.Get<Thread>(handle); |
| 152 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | 168 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); |
| 153 | 169 | ||
| 170 | // Release all the mutexes that this thread holds | ||
| 171 | ReleaseThreadMutexes(handle); | ||
| 172 | |||
| 154 | ChangeReadyState(thread, false); | 173 | ChangeReadyState(thread, false); |
| 155 | thread->status = THREADSTATUS_DORMANT; | 174 | thread->status = THREADSTATUS_DORMANT; |
| 156 | for (Handle waiting_handle : thread->waiting_threads) { | 175 | for (Handle waiting_handle : thread->waiting_threads) { |
| 157 | Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); | 176 | Thread* waiting_thread = g_handle_table.Get<Thread>(waiting_handle); |
| 158 | if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | 177 | |
| 178 | if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle)) | ||
| 159 | ResumeThreadFromWait(waiting_handle); | 179 | ResumeThreadFromWait(waiting_handle); |
| 160 | } | ||
| 161 | } | 180 | } |
| 162 | thread->waiting_threads.clear(); | 181 | thread->waiting_threads.clear(); |
| 163 | 182 | ||
| 164 | // Stopped threads are never waiting. | 183 | // Stopped threads are never waiting. |
| 165 | thread->wait_type = WAITTYPE_NONE; | 184 | thread->wait_type = WAITTYPE_NONE; |
| 166 | thread->wait_handle = 0; | 185 | thread->wait_handle = 0; |
| 186 | thread->wait_address = 0; | ||
| 167 | 187 | ||
| 168 | return RESULT_SUCCESS; | 188 | return RESULT_SUCCESS; |
| 169 | } | 189 | } |
| @@ -178,7 +198,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 178 | 198 | ||
| 179 | if (new_status == THREADSTATUS_WAIT) { | 199 | if (new_status == THREADSTATUS_WAIT) { |
| 180 | if (t->wait_type == WAITTYPE_NONE) { | 200 | if (t->wait_type == WAITTYPE_NONE) { |
| 181 | ERROR_LOG(KERNEL, "Waittype none not allowed"); | 201 | LOG_ERROR(Kernel, "Waittype none not allowed"); |
| 182 | } | 202 | } |
| 183 | } | 203 | } |
| 184 | } | 204 | } |
| @@ -190,14 +210,14 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||
| 190 | 210 | ||
| 191 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 211 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 192 | for (Handle handle : thread_queue) { | 212 | for (Handle handle : thread_queue) { |
| 193 | Thread* thread = g_object_pool.Get<Thread>(handle); | 213 | Thread* thread = g_handle_table.Get<Thread>(handle); |
| 194 | 214 | ||
| 195 | // TODO(bunnei): Verify arbiter address... | 215 | if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 196 | if (!VerifyWait(thread, WAITTYPE_ARB, arbiter)) | ||
| 197 | continue; | 216 | continue; |
| 198 | 217 | ||
| 199 | if (thread == nullptr) | 218 | if (thread == nullptr) |
| 200 | continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. | 219 | continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. |
| 220 | |||
| 201 | if(thread->current_priority <= priority) { | 221 | if(thread->current_priority <= priority) { |
| 202 | highest_priority_thread = handle; | 222 | highest_priority_thread = handle; |
| 203 | priority = thread->current_priority; | 223 | priority = thread->current_priority; |
| @@ -215,10 +235,9 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) { | |||
| 215 | 235 | ||
| 216 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 236 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 217 | for (Handle handle : thread_queue) { | 237 | for (Handle handle : thread_queue) { |
| 218 | Thread* thread = g_object_pool.Get<Thread>(handle); | 238 | Thread* thread = g_handle_table.Get<Thread>(handle); |
| 219 | 239 | ||
| 220 | // TODO(bunnei): Verify arbiter address... | 240 | if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) |
| 221 | if (VerifyWait(thread, WAITTYPE_ARB, arbiter)) | ||
| 222 | ResumeThreadFromWait(handle); | 241 | ResumeThreadFromWait(handle); |
| 223 | } | 242 | } |
| 224 | } | 243 | } |
| @@ -269,14 +288,9 @@ Thread* NextThread() { | |||
| 269 | if (next == 0) { | 288 | if (next == 0) { |
| 270 | return nullptr; | 289 | return nullptr; |
| 271 | } | 290 | } |
| 272 | return Kernel::g_object_pool.Get<Thread>(next); | 291 | return Kernel::g_handle_table.Get<Thread>(next); |
| 273 | } | 292 | } |
| 274 | 293 | ||
| 275 | /** | ||
| 276 | * Puts the current thread in the wait state for the given type | ||
| 277 | * @param wait_type Type of wait | ||
| 278 | * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread | ||
| 279 | */ | ||
| 280 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { | 294 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { |
| 281 | Thread* thread = GetCurrentThread(); | 295 | Thread* thread = GetCurrentThread(); |
| 282 | thread->wait_type = wait_type; | 296 | thread->wait_type = wait_type; |
| @@ -284,11 +298,18 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { | |||
| 284 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | 298 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); |
| 285 | } | 299 | } |
| 286 | 300 | ||
| 301 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address) { | ||
| 302 | WaitCurrentThread(wait_type, wait_handle); | ||
| 303 | GetCurrentThread()->wait_address = wait_address; | ||
| 304 | } | ||
| 305 | |||
| 287 | /// Resumes a thread from waiting by marking it as "ready" | 306 | /// Resumes a thread from waiting by marking it as "ready" |
| 288 | void ResumeThreadFromWait(Handle handle) { | 307 | void ResumeThreadFromWait(Handle handle) { |
| 289 | Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); | 308 | Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); |
| 290 | if (thread) { | 309 | if (thread) { |
| 291 | thread->status &= ~THREADSTATUS_WAIT; | 310 | thread->status &= ~THREADSTATUS_WAIT; |
| 311 | thread->wait_handle = 0; | ||
| 312 | thread->wait_type = WAITTYPE_NONE; | ||
| 292 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | 313 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 293 | ChangeReadyState(thread, true); | 314 | ChangeReadyState(thread, true); |
| 294 | } | 315 | } |
| @@ -301,12 +322,12 @@ void DebugThreadQueue() { | |||
| 301 | if (!thread) { | 322 | if (!thread) { |
| 302 | return; | 323 | return; |
| 303 | } | 324 | } |
| 304 | INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); | 325 | LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); |
| 305 | for (u32 i = 0; i < thread_queue.size(); i++) { | 326 | for (u32 i = 0; i < thread_queue.size(); i++) { |
| 306 | Handle handle = thread_queue[i]; | 327 | Handle handle = thread_queue[i]; |
| 307 | s32 priority = thread_ready_queue.contains(handle); | 328 | s32 priority = thread_ready_queue.contains(handle); |
| 308 | if (priority != -1) { | 329 | if (priority != -1) { |
| 309 | INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); | 330 | LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, handle); |
| 310 | } | 331 | } |
| 311 | } | 332 | } |
| 312 | } | 333 | } |
| @@ -316,15 +337,17 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio | |||
| 316 | s32 processor_id, u32 stack_top, int stack_size) { | 337 | s32 processor_id, u32 stack_top, int stack_size) { |
| 317 | 338 | ||
| 318 | _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), | 339 | _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), |
| 319 | "CreateThread priority=%d, outside of allowable range!", priority) | 340 | "priority=%d, outside of allowable range!", priority) |
| 320 | 341 | ||
| 321 | Thread* thread = new Thread; | 342 | Thread* thread = new Thread; |
| 322 | 343 | ||
| 323 | handle = Kernel::g_object_pool.Create(thread); | 344 | // TOOD(yuriks): Fix error reporting |
| 345 | handle = Kernel::g_handle_table.Create(thread).ValueOr(INVALID_HANDLE); | ||
| 324 | 346 | ||
| 325 | thread_queue.push_back(handle); | 347 | thread_queue.push_back(handle); |
| 326 | thread_ready_queue.prepare(priority); | 348 | thread_ready_queue.prepare(priority); |
| 327 | 349 | ||
| 350 | thread->thread_id = next_thread_id++; | ||
| 328 | thread->status = THREADSTATUS_DORMANT; | 351 | thread->status = THREADSTATUS_DORMANT; |
| 329 | thread->entry_point = entry_point; | 352 | thread->entry_point = entry_point; |
| 330 | thread->stack_top = stack_top; | 353 | thread->stack_top = stack_top; |
| @@ -333,6 +356,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio | |||
| 333 | thread->processor_id = processor_id; | 356 | thread->processor_id = processor_id; |
| 334 | thread->wait_type = WAITTYPE_NONE; | 357 | thread->wait_type = WAITTYPE_NONE; |
| 335 | thread->wait_handle = 0; | 358 | thread->wait_handle = 0; |
| 359 | thread->wait_address = 0; | ||
| 336 | thread->name = name; | 360 | thread->name = name; |
| 337 | 361 | ||
| 338 | return thread; | 362 | return thread; |
| @@ -343,24 +367,24 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 | |||
| 343 | u32 stack_top, int stack_size) { | 367 | u32 stack_top, int stack_size) { |
| 344 | 368 | ||
| 345 | if (name == nullptr) { | 369 | if (name == nullptr) { |
| 346 | ERROR_LOG(KERNEL, "CreateThread(): nullptr name"); | 370 | LOG_ERROR(Kernel_SVC, "nullptr name"); |
| 347 | return -1; | 371 | return -1; |
| 348 | } | 372 | } |
| 349 | if ((u32)stack_size < 0x200) { | 373 | if ((u32)stack_size < 0x200) { |
| 350 | ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, | 374 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid stack_size=0x%08X", name, |
| 351 | stack_size); | 375 | stack_size); |
| 352 | return -1; | 376 | return -1; |
| 353 | } | 377 | } |
| 354 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | 378 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { |
| 355 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | 379 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| 356 | WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X", | 380 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", |
| 357 | name, priority, new_priority); | 381 | name, priority, new_priority); |
| 358 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | 382 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm |
| 359 | // validity of this | 383 | // validity of this |
| 360 | priority = new_priority; | 384 | priority = new_priority; |
| 361 | } | 385 | } |
| 362 | if (!Memory::GetPointer(entry_point)) { | 386 | if (!Memory::GetPointer(entry_point)) { |
| 363 | ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point); | 387 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point); |
| 364 | return -1; | 388 | return -1; |
| 365 | } | 389 | } |
| 366 | Handle handle; | 390 | Handle handle; |
| @@ -375,7 +399,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 | |||
| 375 | 399 | ||
| 376 | /// Get the priority of the thread specified by handle | 400 | /// Get the priority of the thread specified by handle |
| 377 | ResultVal<u32> GetThreadPriority(const Handle handle) { | 401 | ResultVal<u32> GetThreadPriority(const Handle handle) { |
| 378 | Thread* thread = g_object_pool.Get<Thread>(handle); | 402 | Thread* thread = g_handle_table.Get<Thread>(handle); |
| 379 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | 403 | if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); |
| 380 | 404 | ||
| 381 | return MakeResult<u32>(thread->current_priority); | 405 | return MakeResult<u32>(thread->current_priority); |
| @@ -387,7 +411,7 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) { | |||
| 387 | if (!handle) { | 411 | if (!handle) { |
| 388 | thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? | 412 | thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? |
| 389 | } else { | 413 | } else { |
| 390 | thread = g_object_pool.Get<Thread>(handle); | 414 | thread = g_handle_table.Get<Thread>(handle); |
| 391 | if (thread == nullptr) { | 415 | if (thread == nullptr) { |
| 392 | return InvalidHandle(ErrorModule::Kernel); | 416 | return InvalidHandle(ErrorModule::Kernel); |
| 393 | } | 417 | } |
| @@ -397,7 +421,7 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) { | |||
| 397 | // If priority is invalid, clamp to valid range | 421 | // If priority is invalid, clamp to valid range |
| 398 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | 422 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { |
| 399 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | 423 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| 400 | WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority); | 424 | LOG_WARNING(Kernel_SVC, "invalid priority=%d, clamping to %d", priority, new_priority); |
| 401 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | 425 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm |
| 402 | // validity of this | 426 | // validity of this |
| 403 | priority = new_priority; | 427 | priority = new_priority; |
| @@ -450,24 +474,44 @@ void Reschedule() { | |||
| 450 | Thread* prev = GetCurrentThread(); | 474 | Thread* prev = GetCurrentThread(); |
| 451 | Thread* next = NextThread(); | 475 | Thread* next = NextThread(); |
| 452 | HLE::g_reschedule = false; | 476 | HLE::g_reschedule = false; |
| 453 | if (next > 0) { | ||
| 454 | INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 455 | 477 | ||
| 478 | if (next != nullptr) { | ||
| 479 | LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 456 | SwitchContext(next); | 480 | SwitchContext(next); |
| 481 | } else { | ||
| 482 | LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); | ||
| 457 | 483 | ||
| 458 | // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep | 484 | for (Handle handle : thread_queue) { |
| 459 | // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. | 485 | Thread* thread = g_handle_table.Get<Thread>(handle); |
| 460 | // This results in the current thread yielding on a VBLANK once, and then it will be | 486 | LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", |
| 461 | // immediately placed back in the queue for execution. | 487 | thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); |
| 462 | if (prev->wait_type == WAITTYPE_VBLANK) { | ||
| 463 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 464 | } | 488 | } |
| 465 | } | 489 | } |
| 490 | |||
| 491 | // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put | ||
| 492 | // to sleep. So, we'll just immediately set it to "ready" again after an attempted context | ||
| 493 | // switch has occurred. This results in the current thread yielding on a sleep once, and then it | ||
| 494 | // will immediately be placed back in the queue for execution. | ||
| 495 | |||
| 496 | if (CheckWaitType(prev, WAITTYPE_SLEEP)) | ||
| 497 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 498 | } | ||
| 499 | |||
| 500 | ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||
| 501 | Thread* thread = g_handle_table.Get<Thread>(handle); | ||
| 502 | if (thread == nullptr) | ||
| 503 | return ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS, | ||
| 504 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 505 | |||
| 506 | *thread_id = thread->thread_id; | ||
| 507 | |||
| 508 | return RESULT_SUCCESS; | ||
| 466 | } | 509 | } |
| 467 | 510 | ||
| 468 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 511 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 469 | 512 | ||
| 470 | void ThreadingInit() { | 513 | void ThreadingInit() { |
| 514 | next_thread_id = INITIAL_THREAD_ID; | ||
| 471 | } | 515 | } |
| 472 | 516 | ||
| 473 | void ThreadingShutdown() { | 517 | void ThreadingShutdown() { |