diff options
| author | 2015-01-17 02:03:44 -0500 | |
|---|---|---|
| committer | 2015-01-21 19:09:03 -0500 | |
| commit | 7faf2d8e06e705d1866fa0d7848ff43541a4b172 (patch) | |
| tree | 7cca6433c6b06a1299af1193df2cedac7ad522c5 /src/core/hle/svc.cpp | |
| parent | Event: Fixed some bugs and cleanup (Subv) (diff) | |
| download | yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.gz yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.xz yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.zip | |
WaitSynchronizationN: Implement return values
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 77 |
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 |
| 143 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, | 146 | static 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 | } |