diff options
| author | 2015-01-18 01:27:46 -0500 | |
|---|---|---|
| committer | 2015-01-21 19:11:47 -0500 | |
| commit | 6643673f28b9273149fc945849a13ed832e9ef33 (patch) | |
| tree | 026410cf5b0b57d350ac979380307991646e546c /src/core/hle/svc.cpp | |
| 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
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 52 |
1 files changed, 27 insertions, 25 deletions
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... |