summaryrefslogtreecommitdiff
path: root/src/core/hle/svc.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2015-01-18 01:27:46 -0500
committerGravatar bunnei2015-01-21 19:11:47 -0500
commit6643673f28b9273149fc945849a13ed832e9ef33 (patch)
tree026410cf5b0b57d350ac979380307991646e546c /src/core/hle/svc.cpp
parentKernel: Separate WaitSynchronization into Wait and Acquire methods. (diff)
downloadyuzu-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.cpp52
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
148static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { 148static 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...