From 3fb31fbc57fd1d537db79af898ef26c92b0e0867 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 1 Jun 2014 22:12:54 -0400 Subject: [PATCH] svc: added GetThreadPriority and SetThreadPriority, added (incomplete) DuplicateHandle support --- src/core/hle/kernel/thread.cpp | 45 ++++++++++++++++++++++++++++++++++ src/core/hle/kernel/thread.h | 6 +++++ src/core/hle/svc.cpp | 29 +++++++++++++++++++--- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f2094f7a71..c84fdf91d2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -294,6 +294,51 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 return handle; } +/// Get the priority of the thread specified by handle +u32 GetThreadPriority(const Handle handle) { + Thread* thread = g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, thread, "called, but thread is NULL!"); + return thread->current_priority; +} + +/// Set the priority of the thread specified by handle +Result SetThreadPriority(Handle handle, s32 priority) { + Thread* thread = NULL; + if (!handle) { + thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? + } else { + thread = g_object_pool.GetFast(handle); + } + _assert_msg_(KERNEL, thread, "called, but thread is NULL!"); + + // If priority is invalid, clamp to valid range + if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { + s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); + WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority); + // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm + // validity of this + priority = new_priority; + } + + // Change thread priority + s32 old = thread->current_priority; + g_thread_ready_queue.remove(old, handle); + thread->current_priority = priority; + g_thread_ready_queue.prepare(thread->current_priority); + + // Change thread status to "ready" and push to ready queue + if (thread->IsRunning()) { + thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; + } + if (thread->IsReady()) { + g_thread_ready_queue.push_back(thread->current_priority, handle); + } + + HLE::EatCycles(450); + + return 0; +} + /// Sets up the primary application thread Handle SetupMainThread(s32 priority, int stack_size) { Handle handle; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9628f165d6..094c8d43e6 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -65,6 +65,12 @@ Handle GetCurrentThreadHandle(); /// Put current thread in a wait state - on WaitSynchronization void WaitThread_Synchronization(); +/// Get the priority of the thread specified by handle +u32 GetThreadPriority(const Handle handle); + +/// Set the priority of the thread specified by handle +Result SetThreadPriority(Handle handle, s32 priority); + /// Initialize threading void ThreadingInit(); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 0c2412a65d..2384b7936a 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -258,6 +258,18 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p return 0; } +/// Gets the priority for the specified thread +Result GetThreadPriority(void* _priority, Handle handle) { + s32* priority = (s32*)_priority; + *priority = Kernel::GetThreadPriority(handle); + return 0; +} + +/// Sets the priority for the specified thread +Result SetThreadPriority(Handle handle, s32 priority) { + return Kernel::SetThreadPriority(handle, priority); +} + /// Create a mutex Result CreateMutex(void* _mutex, u32 initial_locked) { Handle* mutex = (Handle*)_mutex; @@ -299,7 +311,18 @@ Result CreateEvent(void* _event, u32 reset_type) { /// Duplicates a kernel handle Result DuplicateHandle(void* _out, Handle handle) { Handle* out = (Handle*)_out; - ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); + ERROR_LOG(SVC, "called handle=0x%08X", handle); + + // Translate kernel handles -> real handles + if (handle == Kernel::CurrentThread) { + handle = Kernel::GetCurrentThreadHandle(); + } + _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), + "(UNIMPLEMENTED) process handle duplication!"); + + // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate. + *out = handle; + return 0; } @@ -327,8 +350,8 @@ const HLE::FunctionDef SVC_Table[] = { {0x08, WrapI_UUUUU, "CreateThread"}, {0x09, NULL, "ExitThread"}, {0x0A, WrapV_S64, "SleepThread"}, - {0x0B, NULL, "GetThreadPriority"}, - {0x0C, NULL, "SetThreadPriority"}, + {0x0B, WrapI_VU, "GetThreadPriority"}, + {0x0C, WrapI_UI, "SetThreadPriority"}, {0x0D, NULL, "GetThreadAffinityMask"}, {0x0E, NULL, "SetThreadAffinityMask"}, {0x0F, NULL, "GetThreadIdealProcessor"},