summaryrefslogtreecommitdiff
path: root/src/core/hle/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/svc.cpp')
-rw-r--r--src/core/hle/svc.cpp77
1 files changed, 50 insertions, 27 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index a487f757c..170ac87f3 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -133,6 +133,9 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
133 if (wait.Succeeded() && *wait) { 133 if (wait.Succeeded() && *wait) {
134 // Create an event to wake the thread up after the specified nanosecond delay has passed 134 // Create an event to wake the thread up after the specified nanosecond delay has passed
135 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); 135 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
136
137 Kernel::GetCurrentThread()->SetWaitAll(false);
138
136 HLE::Reschedule(__func__); 139 HLE::Reschedule(__func__);
137 } 140 }
138 141
@@ -140,44 +143,64 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
140} 143}
141 144
142/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 145/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
143static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, 146static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
144 s64 nano_seconds) { 147 bool wait_thread = false;
145 148 bool wait_all_succeeded = false;
146 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 149 int handle_index = 0;
147 bool unlock_all = true;
148 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
149 150
150 LOG_TRACE(Kernel_SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", 151 while (handle_index < handle_count) {
151 handle_count, (wait_all ? "true" : "false"), nano_seconds); 152 SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[handle_index]);
152
153 // Iterate through each handle, synchronize kernel object
154 for (s32 i = 0; i < handle_count; i++) {
155 SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]);
156 if (object == nullptr) 153 if (object == nullptr)
157 return InvalidHandle(ErrorModule::Kernel).raw; 154 return InvalidHandle(ErrorModule::Kernel).raw;
158 155
159 LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], 156 ResultVal<bool> wait = object->WaitSynchronization(handle_index);
160 object->GetTypeName().c_str(), object->GetName().c_str());
161 157
162 // TODO(yuriks): Verify how the real function behaves when an error happens here 158 wait_thread = (wait.Succeeded() && *wait);
163 ResultVal<bool> wait_result = object->WaitSynchronization();
164 bool wait = wait_result.Succeeded() && *wait_result;
165 159
166 if (!wait && !wait_all) { 160 // If this object waited and we are waiting on all objects to synchronize
167 *out = i; 161 if (wait_thread && wait_all) {
168 return RESULT_SUCCESS.raw; 162 // Enforce later on that this thread does not continue
169 } else { 163 wait_all_succeeded = true;
170 unlock_all = false;
171 } 164 }
165
166 // If this object synchronized and we are not waiting on all objects to synchronize
167 if (!wait_thread && !wait_all)
168 // We're done, the thread will continue
169 break;
170
171 handle_index++;
172 }
173
174 // Change the thread state to waiting if blocking on all handles...
175 if (wait_thread || wait_all_succeeded) {
176 // Create an event to wake the thread up after the specified nanosecond delay has passed
177 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
178 Kernel::GetCurrentThread()->SetWaitAll(wait_all);
179
180 HLE::Reschedule(__func__);
181
182 // NOTE: output of this SVC will be set later depending on how the thread resumes
183 return RESULT_DUMMY.raw;
172 } 184 }
173 185
174 if (wait_all && unlock_all) { 186 // Acquire objects if we did not wait...
175 *out = handle_count; 187 for (int i = 0; i < handle_count; ++i) {
176 return RESULT_SUCCESS.raw; 188 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
189
190 // Acquire the object if it is not waiting...
191 if (!object->ShouldWait()) {
192 object->Acquire();
193
194 // If this was the first non-waiting object and 'wait_all' is false, don't acquire
195 // any other objects
196 if (!wait_all)
197 break;
198 }
177 } 199 }
178 200
179 // Check for next thread to schedule 201 // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
180 HLE::Reschedule(__func__); 202 // not seem to set it to any meaningful value.
203 *out = wait_all ? 0 : handle_index;
181 204
182 return RESULT_SUCCESS.raw; 205 return RESULT_SUCCESS.raw;
183} 206}