summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2014-10-23 01:20:01 -0200
committerGravatar Yuri Kunde Schlesner2014-11-24 17:08:36 -0200
commitc2588403c0b8cf198f13f903f626851c7e94266c (patch)
tree09d26cdae187a47338caf94943291c60b4a40a4c /src/core/hle/kernel/thread.cpp
parentChange some SkyEye defines to const ints (diff)
downloadyuzu-c2588403c0b8cf198f13f903f626851c7e94266c.tar.gz
yuzu-c2588403c0b8cf198f13f903f626851c7e94266c.tar.xz
yuzu-c2588403c0b8cf198f13f903f626851c7e94266c.zip
HLE: Revamp error handling throrough the HLE code
All service calls in the CTR OS return result codes indicating the success or failure of the call. Previous to this commit, Citra's HLE emulation of services and the kernel universally either ignored errors or returned dummy -1 error codes. This commit makes an initial effort to provide an infrastructure for error reporting and propagation which can be use going forward to make HLE calls accurately return errors as the original system. A few parts of the code have been updated to use the new system where applicable. One part of this effort is the definition of the `ResultCode` type, which provides facilities for constructing and parsing error codes in the structured format used by the CTR. The `ResultVal` type builds on `ResultCode` by providing a container for values returned by function that can report errors. It enforces that correct error checking will be done on function returns by preventing the use of the return value if the function returned an error code. Currently this change is mostly internal since errors are still suppressed on the ARM<->HLE border, as a temporary compatibility hack. As functionality is implemented and tested this hack can be eventually removed.
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp51
1 files changed, 30 insertions, 21 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index cc70cbca7..b01779f2e 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -11,10 +11,11 @@
11#include "common/thread_queue_list.h" 11#include "common/thread_queue_list.h"
12 12
13#include "core/core.h" 13#include "core/core.h"
14#include "core/mem_map.h"
15#include "core/hle/hle.h" 14#include "core/hle/hle.h"
16#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "core/hle/result.h"
18#include "core/mem_map.h"
18 19
19namespace Kernel { 20namespace Kernel {
20 21
@@ -38,16 +39,17 @@ public:
38 * @param wait Boolean wait set if current thread should wait as a result of sync operation 39 * @param wait Boolean wait set if current thread should wait as a result of sync operation
39 * @return Result of operation, 0 on success, otherwise error code 40 * @return Result of operation, 0 on success, otherwise error code
40 */ 41 */
41 Result WaitSynchronization(bool* wait) override { 42 ResultVal<bool> WaitSynchronization() override {
42 if (status != THREADSTATUS_DORMANT) { 43 if (status != THREADSTATUS_DORMANT) {
43 Handle thread = GetCurrentThreadHandle(); 44 Handle thread = GetCurrentThreadHandle();
44 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 45 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
45 waiting_threads.push_back(thread); 46 waiting_threads.push_back(thread);
46 } 47 }
47 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); 48 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
48 *wait = true; 49 return MakeResult<bool>(true);
50 } else {
51 return MakeResult<bool>(false);
49 } 52 }
50 return 0;
51 } 53 }
52 54
53 ThreadContext context; 55 ThreadContext context;
@@ -144,9 +146,9 @@ void ChangeReadyState(Thread* t, bool ready) {
144} 146}
145 147
146/// Verify that a thread has not been released from waiting 148/// Verify that a thread has not been released from waiting
147inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { 149inline bool VerifyWait(Handle handle, WaitType type, Handle wait_handle) {
148 Thread* thread = g_object_pool.GetFast<Thread>(handle); 150 Thread* thread = g_object_pool.Get<Thread>(handle);
149 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 151 _dbg_assert_(KERNEL, thread != nullptr);
150 152
151 if (type != thread->wait_type || wait_handle != thread->wait_handle) 153 if (type != thread->wait_type || wait_handle != thread->wait_handle)
152 return false; 154 return false;
@@ -155,9 +157,9 @@ inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle)
155} 157}
156 158
157/// Stops the current thread 159/// Stops the current thread
158void StopThread(Handle handle, const char* reason) { 160ResultCode StopThread(Handle handle, const char* reason) {
159 Thread* thread = g_object_pool.GetFast<Thread>(handle); 161 Thread* thread = g_object_pool.Get<Thread>(handle);
160 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 162 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
161 163
162 ChangeReadyState(thread, false); 164 ChangeReadyState(thread, false);
163 thread->status = THREADSTATUS_DORMANT; 165 thread->status = THREADSTATUS_DORMANT;
@@ -172,6 +174,8 @@ void StopThread(Handle handle, const char* reason) {
172 // Stopped threads are never waiting. 174 // Stopped threads are never waiting.
173 thread->wait_type = WAITTYPE_NONE; 175 thread->wait_type = WAITTYPE_NONE;
174 thread->wait_handle = 0; 176 thread->wait_handle = 0;
177
178 return RESULT_SUCCESS;
175} 179}
176 180
177/// Changes a threads state 181/// Changes a threads state
@@ -201,7 +205,9 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
201 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) 205 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter))
202 continue; 206 continue;
203 207
204 Thread* thread = g_object_pool.GetFast<Thread>(handle); 208 Thread* thread = g_object_pool.Get<Thread>(handle);
209 if (thread == nullptr)
210 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
205 if(thread->current_priority <= priority) { 211 if(thread->current_priority <= priority) {
206 highest_priority_thread = handle; 212 highest_priority_thread = handle;
207 priority = thread->current_priority; 213 priority = thread->current_priority;
@@ -272,7 +278,7 @@ Thread* NextThread() {
272 if (next == 0) { 278 if (next == 0) {
273 return nullptr; 279 return nullptr;
274 } 280 }
275 return Kernel::g_object_pool.GetFast<Thread>(next); 281 return Kernel::g_object_pool.Get<Thread>(next);
276} 282}
277 283
278/** 284/**
@@ -289,8 +295,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
289 295
290/// Resumes a thread from waiting by marking it as "ready" 296/// Resumes a thread from waiting by marking it as "ready"
291void ResumeThreadFromWait(Handle handle) { 297void ResumeThreadFromWait(Handle handle) {
292 u32 error; 298 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
293 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
294 if (thread) { 299 if (thread) {
295 thread->status &= ~THREADSTATUS_WAIT; 300 thread->status &= ~THREADSTATUS_WAIT;
296 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 301 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
@@ -378,19 +383,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
378} 383}
379 384
380/// Get the priority of the thread specified by handle 385/// Get the priority of the thread specified by handle
381u32 GetThreadPriority(const Handle handle) { 386ResultVal<u32> GetThreadPriority(const Handle handle) {
382 Thread* thread = g_object_pool.GetFast<Thread>(handle); 387 Thread* thread = g_object_pool.Get<Thread>(handle);
383 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 388 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
384 return thread->current_priority; 389
390 return MakeResult<u32>(thread->current_priority);
385} 391}
386 392
387/// Set the priority of the thread specified by handle 393/// Set the priority of the thread specified by handle
388Result SetThreadPriority(Handle handle, s32 priority) { 394ResultCode SetThreadPriority(Handle handle, s32 priority) {
389 Thread* thread = nullptr; 395 Thread* thread = nullptr;
390 if (!handle) { 396 if (!handle) {
391 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? 397 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
392 } else { 398 } else {
393 thread = g_object_pool.GetFast<Thread>(handle); 399 thread = g_object_pool.Get<Thread>(handle);
400 if (thread == nullptr) {
401 return InvalidHandle(ErrorModule::Kernel);
402 }
394 } 403 }
395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 404 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
396 405
@@ -417,7 +426,7 @@ Result SetThreadPriority(Handle handle, s32 priority) {
417 thread_ready_queue.push_back(thread->current_priority, handle); 426 thread_ready_queue.push_back(thread->current_priority, handle);
418 } 427 }
419 428
420 return 0; 429 return RESULT_SUCCESS;
421} 430}
422 431
423/// Sets up the primary application thread 432/// Sets up the primary application thread