diff options
| author | 2015-01-18 01:27:46 -0500 | |
|---|---|---|
| committer | 2015-01-21 19:11:47 -0500 | |
| commit | 6643673f28b9273149fc945849a13ed832e9ef33 (patch) | |
| tree | 026410cf5b0b57d350ac979380307991646e546c | |
| parent | Kernel: Separate WaitSynchronization into Wait and Acquire methods. (diff) | |
| download | yuzu-6643673f28b9273149fc945849a13ed832e9ef33.tar.gz yuzu-6643673f28b9273149fc945849a13ed832e9ef33.tar.xz yuzu-6643673f28b9273149fc945849a13ed832e9ef33.zip | |
WaitSynchronizationN: Refactor to fix several bugs
- Separate wait checking from waiting the current thread
- Resume thread when wait_all=true only if all objects are available at once
- Set output to correct wait object index when there are duplicate handles
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 61 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 52 |
8 files changed, 76 insertions, 79 deletions
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 41e1bd6c5..ae9b06b84 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -28,11 +28,11 @@ public: | |||
| 28 | bool signaled; ///< Whether the event has already been signaled | 28 | bool signaled; ///< Whether the event has already been signaled |
| 29 | std::string name; ///< Name of event (optional) | 29 | std::string name; ///< Name of event (optional) |
| 30 | 30 | ||
| 31 | ResultVal<bool> Wait(unsigned index) override { | 31 | ResultVal<bool> Wait(bool wait_thread) override { |
| 32 | bool wait = !signaled; | 32 | bool wait = !signaled; |
| 33 | if (wait) { | 33 | if (wait && wait_thread) { |
| 34 | AddWaitingThread(GetCurrentThread()); | 34 | AddWaitingThread(GetCurrentThread()); |
| 35 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this, index); | 35 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this); |
| 36 | } | 36 | } |
| 37 | return MakeResult<bool>(wait); | 37 | return MakeResult<bool>(wait); |
| 38 | } | 38 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d98fd0389..cfaf0c901 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -65,18 +65,18 @@ public: | |||
| 65 | virtual Kernel::HandleType GetHandleType() const = 0; | 65 | virtual Kernel::HandleType GetHandleType() const = 0; |
| 66 | 66 | ||
| 67 | /** | 67 | /** |
| 68 | * Wait the current thread for kernel object to synchronize. | 68 | * Check if this object is available, (optionally) wait the current thread if not |
| 69 | * @param index Index of wait object (only applies to WaitSynchronizationN) | 69 | * @param wait_thread If true, wait the current thread if this object is unavailable |
| 70 | * @return True if the current thread should wait as a result of the wait | 70 | * @return True if the current thread should wait due to this object being unavailable |
| 71 | */ | 71 | */ |
| 72 | virtual ResultVal<bool> Wait(unsigned index = 0) { | 72 | virtual ResultVal<bool> Wait(bool wait_thread) { |
| 73 | LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); | 73 | LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); |
| 74 | return UnimplementedFunction(ErrorModule::Kernel); | 74 | return UnimplementedFunction(ErrorModule::Kernel); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /** | 77 | /** |
| 78 | * Acquire/lock the kernel object if it is available | 78 | * Acquire/lock the this object if it is available |
| 79 | * @return True if we were able to acquire the kernel object, otherwise false | 79 | * @return True if we were able to acquire this object, otherwise false |
| 80 | */ | 80 | */ |
| 81 | virtual ResultVal<bool> Acquire() { | 81 | virtual ResultVal<bool> Acquire() { |
| 82 | LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); | 82 | LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 37e7be4e7..f97c69a78 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -26,7 +26,7 @@ public: | |||
| 26 | Handle lock_thread; ///< Handle to thread that currently has mutex | 26 | Handle lock_thread; ///< Handle to thread that currently has mutex |
| 27 | std::string name; ///< Name of mutex (optional) | 27 | std::string name; ///< Name of mutex (optional) |
| 28 | 28 | ||
| 29 | ResultVal<bool> Wait(unsigned index) override; | 29 | ResultVal<bool> Wait(bool wait_thread) override; |
| 30 | ResultVal<bool> Acquire() override; | 30 | ResultVal<bool> Acquire() override; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| @@ -156,10 +156,10 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { | |||
| 156 | return handle; | 156 | return handle; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | ResultVal<bool> Mutex::Wait(unsigned index) { | 159 | ResultVal<bool> Mutex::Wait(bool wait_thread) { |
| 160 | if (locked) { | 160 | if (locked && wait_thread) { |
| 161 | AddWaitingThread(GetCurrentThread()); | 161 | AddWaitingThread(GetCurrentThread()); |
| 162 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index); | 162 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this); |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | return MakeResult<bool>(locked); | 165 | return MakeResult<bool>(locked); |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6464b2580..42b5cf704 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -32,11 +32,11 @@ public: | |||
| 32 | return available_count > 0; | 32 | return available_count > 0; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | ResultVal<bool> Wait(unsigned index) override { | 35 | ResultVal<bool> Wait(bool wait_thread) override { |
| 36 | bool wait = !IsAvailable(); | 36 | bool wait = !IsAvailable(); |
| 37 | 37 | ||
| 38 | if (wait) { | 38 | if (wait && wait_thread) { |
| 39 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index); | 39 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this); |
| 40 | AddWaitingThread(GetCurrentThread()); | 40 | AddWaitingThread(GetCurrentThread()); |
| 41 | } | 41 | } |
| 42 | 42 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6b0bdebb5..62b85f56a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | 22 | ||
| 23 | namespace Kernel { | 23 | namespace Kernel { |
| 24 | 24 | ||
| 25 | ResultVal<bool> Thread::Wait(unsigned index) { | 25 | ResultVal<bool> Thread::Wait(bool wait_thread) { |
| 26 | const bool wait = status != THREADSTATUS_DORMANT; | 26 | const bool wait = status != THREADSTATUS_DORMANT; |
| 27 | if (wait) { | 27 | if (wait && wait_thread) { |
| 28 | AddWaitingThread(GetCurrentThread()); | 28 | AddWaitingThread(GetCurrentThread()); |
| 29 | WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); | 29 | WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | return MakeResult<bool>(wait); | 32 | return MakeResult<bool>(wait); |
| @@ -97,7 +97,7 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { | |||
| 97 | /// Check if a thread is blocking on a specified wait type with a specified handle | 97 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 98 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { | 98 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { |
| 99 | for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { | 99 | for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { |
| 100 | if (itr->first == wait_object) | 100 | if (*itr == wait_object) |
| 101 | return CheckWaitType(thread, type); | 101 | return CheckWaitType(thread, type); |
| 102 | } | 102 | } |
| 103 | return false; | 103 | return false; |
| @@ -234,16 +234,7 @@ void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_ | |||
| 234 | Thread* thread = GetCurrentThread(); | 234 | Thread* thread = GetCurrentThread(); |
| 235 | thread->wait_type = wait_type; | 235 | thread->wait_type = wait_type; |
| 236 | 236 | ||
| 237 | bool insert_wait_object = true; | 237 | thread->wait_objects.push_back(wait_object); |
| 238 | for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { | ||
| 239 | if (itr->first == wait_object) { | ||
| 240 | insert_wait_object = false; | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | if (insert_wait_object) | ||
| 246 | thread->wait_objects.push_back(std::pair<SharedPtr<WaitObject>, unsigned>(wait_object, index)); | ||
| 247 | 238 | ||
| 248 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | 239 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); |
| 249 | } | 240 | } |
| @@ -288,31 +279,35 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) { | |||
| 288 | return; | 279 | return; |
| 289 | } | 280 | } |
| 290 | 281 | ||
| 291 | // Remove this thread from the wait_object | 282 | // Remove this thread from the waiting object's thread list |
| 292 | wait_object->RemoveWaitingThread(this); | 283 | wait_object->RemoveWaitingThread(this); |
| 293 | 284 | ||
| 294 | // Find the waiting object | 285 | unsigned index = 0; |
| 295 | auto itr = wait_objects.begin(); | 286 | bool wait_all_failed = false; // Will be set to true if any object is unavailable |
| 296 | for (; itr != wait_objects.end(); ++itr) { | ||
| 297 | if (wait_object == itr->first) | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | unsigned index = itr->second; | ||
| 301 | 287 | ||
| 302 | // Remove the wait_object from this thread | 288 | // Iterate through all waiting objects to check availability... |
| 303 | if (itr != wait_objects.end()) | 289 | for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { |
| 304 | wait_objects.erase(itr); | 290 | auto res = (*itr)->Wait(false); |
| 305 | 291 | ||
| 306 | // If wait_all=false, resume the thread on a release wait_object from wait | 292 | if (*res && res.Succeeded()) |
| 307 | if (!wait_all) { | 293 | wait_all_failed = true; |
| 308 | SetReturnValue(RESULT_SUCCESS, index); | 294 | |
| 309 | ResumeFromWait(); | 295 | // The output should be the last index of wait_object |
| 310 | } else { | 296 | if (*itr == wait_object) |
| 311 | // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released | 297 | index = itr - wait_objects.begin(); |
| 312 | if (wait_objects.empty()) { | 298 | } |
| 299 | |||
| 300 | // If we are waiting on all objects... | ||
| 301 | if (wait_all) { | ||
| 302 | // Resume the thread only if all are available... | ||
| 303 | if (!wait_all_failed) { | ||
| 313 | SetReturnValue(RESULT_SUCCESS, -1); | 304 | SetReturnValue(RESULT_SUCCESS, -1); |
| 314 | ResumeFromWait(); | 305 | ResumeFromWait(); |
| 315 | } | 306 | } |
| 307 | } else { | ||
| 308 | // Otherwise, resume | ||
| 309 | SetReturnValue(RESULT_SUCCESS, index); | ||
| 310 | ResumeFromWait(); | ||
| 316 | } | 311 | } |
| 317 | } | 312 | } |
| 318 | 313 | ||
| @@ -324,7 +319,7 @@ void Thread::ResumeFromWait() { | |||
| 324 | 319 | ||
| 325 | // Remove this thread from all other WaitObjects | 320 | // Remove this thread from all other WaitObjects |
| 326 | for (auto wait_object : wait_objects) | 321 | for (auto wait_object : wait_objects) |
| 327 | wait_object.first->RemoveWaitingThread(this); | 322 | wait_object->RemoveWaitingThread(this); |
| 328 | 323 | ||
| 329 | wait_objects.clear(); | 324 | wait_objects.clear(); |
| 330 | 325 | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9faf89c15..dff6bbaec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -70,7 +70,7 @@ public: | |||
| 70 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | 70 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } |
| 71 | inline bool IsIdle() const { return idle; } | 71 | inline bool IsIdle() const { return idle; } |
| 72 | 72 | ||
| 73 | ResultVal<bool> Wait(unsigned index) override; | 73 | ResultVal<bool> Wait(bool wait_thread) override; |
| 74 | ResultVal<bool> Acquire() override; | 74 | ResultVal<bool> Acquire() override; |
| 75 | 75 | ||
| 76 | s32 GetPriority() const { return current_priority; } | 76 | s32 GetPriority() const { return current_priority; } |
| @@ -117,7 +117,7 @@ public: | |||
| 117 | s32 processor_id; | 117 | s32 processor_id; |
| 118 | 118 | ||
| 119 | WaitType wait_type; | 119 | WaitType wait_type; |
| 120 | std::vector<std::pair<SharedPtr<WaitObject>, unsigned>> wait_objects; | 120 | std::vector<SharedPtr<WaitObject>> wait_objects; |
| 121 | VAddr wait_address; | 121 | VAddr wait_address; |
| 122 | 122 | ||
| 123 | std::string name; | 123 | std::string name; |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 6497bb349..9f0fbafe2 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -29,11 +29,11 @@ public: | |||
| 29 | u64 initial_delay; ///< The delay until the timer fires for the first time | 29 | u64 initial_delay; ///< The delay until the timer fires for the first time |
| 30 | u64 interval_delay; ///< The delay until the timer fires after the first time | 30 | u64 interval_delay; ///< The delay until the timer fires after the first time |
| 31 | 31 | ||
| 32 | ResultVal<bool> Wait(unsigned index) override { | 32 | ResultVal<bool> Wait(bool wait_thread) override { |
| 33 | bool wait = !signaled; | 33 | bool wait = !signaled; |
| 34 | if (wait) { | 34 | if (wait && wait_thread) { |
| 35 | AddWaitingThread(GetCurrentThread()); | 35 | AddWaitingThread(GetCurrentThread()); |
| 36 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this, index); | 36 | Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this); |
| 37 | } | 37 | } |
| 38 | return MakeResult<bool>(wait); | 38 | return MakeResult<bool>(wait); |
| 39 | } | 39 | } |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index a27aa6269..059451100 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -127,7 +127,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 127 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, | 127 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, |
| 128 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); | 128 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); |
| 129 | 129 | ||
| 130 | ResultVal<bool> wait = object->Wait(); | 130 | ResultVal<bool> wait = object->Wait(true); |
| 131 | 131 | ||
| 132 | // Check for next thread to schedule | 132 | // Check for next thread to schedule |
| 133 | if (wait.Succeeded() && *wait) { | 133 | if (wait.Succeeded() && *wait) { |
| @@ -146,8 +146,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 146 | 146 | ||
| 147 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 147 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 148 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | 148 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { |
| 149 | bool wait_thread = false; | 149 | bool wait_thread = !wait_all; |
| 150 | bool wait_all_succeeded = false; | ||
| 151 | int handle_index = 0; | 150 | int handle_index = 0; |
| 152 | 151 | ||
| 153 | // Handles pointer is invalid | 152 | // Handles pointer is invalid |
| @@ -158,40 +157,43 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 158 | if (handle_count < 0) | 157 | if (handle_count < 0) |
| 159 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; | 158 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; |
| 160 | 159 | ||
| 161 | // If handle_count is non-zero, iterate through them and wait/acquire the objects as needed | 160 | // If handle_count is non-zero, iterate through them and wait the current thread on the objects |
| 162 | if (handle_count != 0) { | 161 | if (handle_count != 0) { |
| 163 | while (handle_index < handle_count) { | 162 | bool selected = false; // True once an object has been selected |
| 164 | SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[handle_index]); | 163 | for (int i = 0; i < handle_count; ++i) { |
| 164 | SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]); | ||
| 165 | if (object == nullptr) | 165 | if (object == nullptr) |
| 166 | return InvalidHandle(ErrorModule::Kernel).raw; | 166 | return InvalidHandle(ErrorModule::Kernel).raw; |
| 167 | 167 | ||
| 168 | ResultVal<bool> wait = object->Wait(handle_index); | 168 | ResultVal<bool> wait = object->Wait(true); |
| 169 | 169 | ||
| 170 | wait_thread = (wait.Succeeded() && *wait); | 170 | // Check if the current thread should wait on the object... |
| 171 | 171 | if (wait.Succeeded() && *wait) { | |
| 172 | // If this object waited and we are waiting on all objects to synchronize | 172 | // Check we are waiting on all objects... |
| 173 | if (wait_thread && wait_all) | 173 | if (wait_all) |
| 174 | // Enforce later on that this thread does not continue | 174 | // Wait the thread |
| 175 | wait_all_succeeded = true; | 175 | wait_thread = true; |
| 176 | 176 | } else { | |
| 177 | // If this object synchronized and we are not waiting on all objects to synchronize | 177 | // Do not wait on this object, check if this object should be selected... |
| 178 | if (!wait_thread && !wait_all) | 178 | if (!wait_all && !selected) { |
| 179 | // We're done, the thread will continue | 179 | // Do not wait the thread |
| 180 | break; | 180 | wait_thread = false; |
| 181 | 181 | handle_index = i; | |
| 182 | handle_index++; | 182 | selected = true; |
| 183 | } | ||
| 184 | } | ||
| 183 | } | 185 | } |
| 184 | } else { | 186 | } else { |
| 185 | // If no handles were passed in, put the thread to sleep only when wait_all=false | 187 | // If no handles were passed in, put the thread to sleep only when wait_all=false |
| 186 | // NOTE: This is supposed to deadlock if no timeout was specified | 188 | // NOTE: This is supposed to deadlock the current thread if no timeout was specified |
| 187 | if (!wait_all) { | 189 | if (!wait_all) { |
| 188 | wait_thread = true; | 190 | wait_thread = true; |
| 189 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | 191 | Kernel::WaitCurrentThread(WAITTYPE_SLEEP); |
| 190 | } | 192 | } |
| 191 | } | 193 | } |
| 192 | 194 | ||
| 193 | // Change the thread state to waiting if blocking on all handles... | 195 | // If thread should block, then set its state to waiting and then reschedule... |
| 194 | if (wait_thread || wait_all_succeeded) { | 196 | if (wait_thread) { |
| 195 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 197 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 196 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); | 198 | Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); |
| 197 | Kernel::GetCurrentThread()->SetWaitAll(wait_all); | 199 | Kernel::GetCurrentThread()->SetWaitAll(wait_all); |
| @@ -199,7 +201,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 199 | HLE::Reschedule(__func__); | 201 | HLE::Reschedule(__func__); |
| 200 | 202 | ||
| 201 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 203 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 202 | return RESULT_DUMMY.raw; | 204 | return 0xDEADBEEF; |
| 203 | } | 205 | } |
| 204 | 206 | ||
| 205 | // Acquire objects if we did not wait... | 207 | // Acquire objects if we did not wait... |