diff options
| author | 2014-06-05 22:35:36 -0400 | |
|---|---|---|
| committer | 2014-06-13 09:51:02 -0400 | |
| commit | f5c7c1543434e25a215286e6db5e71c055ba48cf (patch) | |
| tree | 488a3fd0c01051453c6f8ccc4867f6b6ea3f2843 /src/core/hle/svc.cpp | |
| parent | qt: updated disassembler to show 2X as many instructions (diff) | |
| download | yuzu-f5c7c1543434e25a215286e6db5e71c055ba48cf.tar.gz yuzu-f5c7c1543434e25a215286e6db5e71c055ba48cf.tar.xz yuzu-f5c7c1543434e25a215286e6db5e71c055ba48cf.zip | |
Kernel: Added real support for thread and event blocking
- SVC: Added ExitThread support
- SVC: Added SignalEvent support
- Thread: Added WAITTYPE_EVENT for waiting threads for event signals
- Thread: Added support for blocking on other threads to finish (e.g. Thread::Join)
- Thread: Added debug function for printing current threads ready for execution
- Thread: Removed hack/broken thread ready state code from Kernel::Reschedule
- Mutex: Moved WaitCurrentThread from SVC to Mutex::WaitSynchronization
- Event: Added support for blocking threads on event signalling
Kernel: Added missing algorithm #include for use of std::find on non-Windows platforms.
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 59 |
1 files changed, 31 insertions, 28 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c8eb8ea80..0ce831103 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -93,8 +93,8 @@ Result SendSyncRequest(Handle handle) { | |||
| 93 | bool wait = false; | 93 | bool wait = false; |
| 94 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | 94 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); |
| 95 | 95 | ||
| 96 | DEBUG_LOG(SVC, "called handle=0x%08X", handle); | ||
| 97 | _assert_msg_(KERNEL, object, "called, but kernel object is NULL!"); | 96 | _assert_msg_(KERNEL, object, "called, but kernel object is NULL!"); |
| 97 | DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName()); | ||
| 98 | 98 | ||
| 99 | Result res = object->SyncRequest(&wait); | 99 | Result res = object->SyncRequest(&wait); |
| 100 | if (wait) { | 100 | if (wait) { |
| @@ -115,29 +115,21 @@ Result CloseHandle(Handle handle) { | |||
| 115 | Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | 115 | Result WaitSynchronization1(Handle handle, s64 nano_seconds) { |
| 116 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this | 116 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this |
| 117 | bool wait = false; | 117 | bool wait = false; |
| 118 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | ||
| 118 | 119 | ||
| 119 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | 120 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); |
| 120 | 121 | ||
| 121 | DEBUG_LOG(SVC, "called handle=0x%08X, nanoseconds=%d", handle, | 122 | DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName(), |
| 122 | nano_seconds); | 123 | object->GetName(), nano_seconds); |
| 124 | |||
| 123 | _assert_msg_(KERNEL, object, "called, but kernel object is NULL!"); | 125 | _assert_msg_(KERNEL, object, "called, but kernel object is NULL!"); |
| 124 | 126 | ||
| 125 | Result res = object->WaitSynchronization(&wait); | 127 | Result res = object->WaitSynchronization(&wait); |
| 126 | 128 | ||
| 129 | // Check for next thread to schedule | ||
| 127 | if (wait) { | 130 | if (wait) { |
| 128 | // Set current thread to wait state if handle was not unlocked | ||
| 129 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | ||
| 130 | |||
| 131 | // Check for next thread to schedule | ||
| 132 | HLE::Reschedule(__func__); | 131 | HLE::Reschedule(__func__); |
| 133 | 132 | return 0; | |
| 134 | // Context switch - Function blocked, is not actually returning (will be "called" again) | ||
| 135 | |||
| 136 | // TODO(bunnei): This saves handle to R0 so that it's correctly reloaded on context switch | ||
| 137 | // (otherwise R0 will be set to whatever is returned, and handle will be invalid when this | ||
| 138 | // thread is resumed). There is probably a better way of keeping track of state so that we | ||
| 139 | // don't necessarily have to do this. | ||
| 140 | return (Result)PARAM(0); | ||
| 141 | } | 133 | } |
| 142 | 134 | ||
| 143 | return res; | 135 | return res; |
| @@ -150,6 +142,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa | |||
| 150 | s32* out = (s32*)_out; | 142 | s32* out = (s32*)_out; |
| 151 | Handle* handles = (Handle*)_handles; | 143 | Handle* handles = (Handle*)_handles; |
| 152 | bool unlock_all = true; | 144 | bool unlock_all = true; |
| 145 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | ||
| 153 | 146 | ||
| 154 | DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", | 147 | DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", |
| 155 | handle_count, (wait_all ? "true" : "false"), nano_seconds); | 148 | handle_count, (wait_all ? "true" : "false"), nano_seconds); |
| @@ -162,7 +155,8 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa | |||
| 162 | _assert_msg_(KERNEL, object, "called handle=0x%08X, but kernel object " | 155 | _assert_msg_(KERNEL, object, "called handle=0x%08X, but kernel object " |
| 163 | "is NULL!", handles[i]); | 156 | "is NULL!", handles[i]); |
| 164 | 157 | ||
| 165 | DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X", i, handles[i]); | 158 | DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName(), |
| 159 | object->GetName()); | ||
| 166 | 160 | ||
| 167 | Result res = object->WaitSynchronization(&wait); | 161 | Result res = object->WaitSynchronization(&wait); |
| 168 | 162 | ||
| @@ -179,19 +173,10 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa | |||
| 179 | return 0; | 173 | return 0; |
| 180 | } | 174 | } |
| 181 | 175 | ||
| 182 | // Set current thread to wait state if not all handles were unlocked | ||
| 183 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | ||
| 184 | |||
| 185 | // Check for next thread to schedule | 176 | // Check for next thread to schedule |
| 186 | HLE::Reschedule(__func__); | 177 | HLE::Reschedule(__func__); |
| 187 | 178 | ||
| 188 | // Context switch - Function blocked, is not actually returning (will be "called" again) | 179 | return 0; |
| 189 | |||
| 190 | // TODO(bunnei): This saves handle to R0 so that it's correctly reloaded on context switch | ||
| 191 | // (otherwise R0 will be set to whatever is returned, and handle will be invalid when this | ||
| 192 | // thread is resumed). There is probably a better way of keeping track of state so that we | ||
| 193 | // don't necessarily have to do this. | ||
| 194 | return (Result)PARAM(0); | ||
| 195 | } | 180 | } |
| 196 | 181 | ||
| 197 | /// Create an address arbiter (to allocate access to shared resources) | 182 | /// Create an address arbiter (to allocate access to shared resources) |
| @@ -258,6 +243,17 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p | |||
| 258 | return 0; | 243 | return 0; |
| 259 | } | 244 | } |
| 260 | 245 | ||
| 246 | /// Called when a thread exits | ||
| 247 | u32 ExitThread() { | ||
| 248 | Handle thread = Kernel::GetCurrentThreadHandle(); | ||
| 249 | |||
| 250 | DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C | ||
| 251 | |||
| 252 | Kernel::StopThread(thread, __func__); | ||
| 253 | HLE::Reschedule(__func__); | ||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 261 | /// Gets the priority for the specified thread | 257 | /// Gets the priority for the specified thread |
| 262 | Result GetThreadPriority(void* _priority, Handle handle) { | 258 | Result GetThreadPriority(void* _priority, Handle handle) { |
| 263 | s32* priority = (s32*)_priority; | 259 | s32* priority = (s32*)_priority; |
| @@ -326,6 +322,13 @@ Result DuplicateHandle(void* _out, Handle handle) { | |||
| 326 | return 0; | 322 | return 0; |
| 327 | } | 323 | } |
| 328 | 324 | ||
| 325 | /// Signals an event | ||
| 326 | Result SignalEvent(Handle evt) { | ||
| 327 | Result res = Kernel::SignalEvent(evt); | ||
| 328 | DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||
| 329 | return res; | ||
| 330 | } | ||
| 331 | |||
| 329 | /// Clears an event | 332 | /// Clears an event |
| 330 | Result ClearEvent(Handle evt) { | 333 | Result ClearEvent(Handle evt) { |
| 331 | Result res = Kernel::ClearEvent(evt); | 334 | Result res = Kernel::ClearEvent(evt); |
| @@ -348,7 +351,7 @@ const HLE::FunctionDef SVC_Table[] = { | |||
| 348 | {0x06, NULL, "GetProcessIdealProcessor"}, | 351 | {0x06, NULL, "GetProcessIdealProcessor"}, |
| 349 | {0x07, NULL, "SetProcessIdealProcessor"}, | 352 | {0x07, NULL, "SetProcessIdealProcessor"}, |
| 350 | {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"}, | 353 | {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"}, |
| 351 | {0x09, NULL, "ExitThread"}, | 354 | {0x09, WrapU_V<ExitThread>, "ExitThread"}, |
| 352 | {0x0A, WrapV_S64<SleepThread>, "SleepThread"}, | 355 | {0x0A, WrapV_S64<SleepThread>, "SleepThread"}, |
| 353 | {0x0B, WrapI_VU<GetThreadPriority>, "GetThreadPriority"}, | 356 | {0x0B, WrapI_VU<GetThreadPriority>, "GetThreadPriority"}, |
| 354 | {0x0C, WrapI_UI<SetThreadPriority>, "SetThreadPriority"}, | 357 | {0x0C, WrapI_UI<SetThreadPriority>, "SetThreadPriority"}, |
| @@ -363,7 +366,7 @@ const HLE::FunctionDef SVC_Table[] = { | |||
| 363 | {0x15, NULL, "CreateSemaphore"}, | 366 | {0x15, NULL, "CreateSemaphore"}, |
| 364 | {0x16, NULL, "ReleaseSemaphore"}, | 367 | {0x16, NULL, "ReleaseSemaphore"}, |
| 365 | {0x17, WrapI_VU<CreateEvent>, "CreateEvent"}, | 368 | {0x17, WrapI_VU<CreateEvent>, "CreateEvent"}, |
| 366 | {0x18, NULL, "SignalEvent"}, | 369 | {0x18, WrapI_U<SignalEvent>, "SignalEvent"}, |
| 367 | {0x19, WrapI_U<ClearEvent>, "ClearEvent"}, | 370 | {0x19, WrapI_U<ClearEvent>, "ClearEvent"}, |
| 368 | {0x1A, NULL, "CreateTimer"}, | 371 | {0x1A, NULL, "CreateTimer"}, |
| 369 | {0x1B, NULL, "SetTimer"}, | 372 | {0x1B, NULL, "SetTimer"}, |