From 6b264518a50ce21cb1be55ff3eac4e1c85582cfe Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 May 2014 22:11:18 -0400 Subject: added initial kernel/thread modules --- src/core/hle/kernel/thread.cpp | 228 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 src/core/hle/kernel/thread.cpp (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp new file mode 100644 index 0000000000..0ed35de83f --- /dev/null +++ b/src/core/hle/kernel/thread.cpp @@ -0,0 +1,228 @@ +// Copyright 2014 Citra Emulator Project / PPSSPP Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include +#include +#include +#include + +#include "common/common.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/thread.h" + +// Real CTR struct, don't change the fields. +struct NativeThread { + //u32 Pointer to vtable + //u32 Reference count + //KProcess* Process the thread belongs to (virtual address) + //u32 Thread id + //u32* ptr = *(KThread+0x8C) - 0xB0 + //u32* End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus, + // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000. + //KThread* Previous ? (virtual address) + //KThread* Next ? (virtual address) +}; + +struct ThreadWaitInfo { + u32 wait_value; + u32 timeout_ptr; +}; + +class Thread : public KernelObject { +public: + /*const char *GetName() { return nt.name; }*/ + const char *GetTypeName() { return "Thread"; } + //void GetQuickInfo(char *ptr, int size) + //{ + // sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )", + // context.pc, context.r[13], // 13 is stack pointer + // (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "", + // (nt.status & THREADSTATUS_READY) ? "READY" : "", + // (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "", + // (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "", + // (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "", + // (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "", + // nt.waitType, + // nt.waitID, + // waitInfo.waitValue); + //} + + //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } + //static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; } + //int GetIDType() const { return SCE_KERNEL_TMID_Thread; } + + //bool AllocateStack(u32 &stack_size) { + // FreeStack(); + + // bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0; + // if (nt.attr & PSP_THREAD_ATTR_KERNEL) + // { + // // Allocate stacks for kernel threads (idle) in kernel RAM + // currentStack.start = kernelMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); + // } + // else + // { + // currentStack.start = userMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); + // } + // if (currentStack.start == (u32)-1) + // { + // currentStack.start = 0; + // nt.initialStack = 0; + // ERROR_LOG(KERNEL, "Failed to allocate stack for thread"); + // return false; + // } + + // nt.initialStack = currentStack.start; + // nt.stack_size = stack_size; + // return true; + //} + + //bool FillStack() { + // // Fill the stack. + // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { + // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); + // } + // context.r[MIPS_REG_SP] = currentStack.start + nt.stack_size; + // currentStack.end = context.r[MIPS_REG_SP]; + // // The k0 section is 256 bytes at the top of the stack. + // context.r[MIPS_REG_SP] -= 256; + // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; + // u32 k0 = context.r[MIPS_REG_K0]; + // Memory::Memset(k0, 0, 0x100); + // Memory::Write_U32(GetUID(), k0 + 0xc0); + // Memory::Write_U32(nt.initialStack, k0 + 0xc8); + // Memory::Write_U32(0xffffffff, k0 + 0xf8); + // Memory::Write_U32(0xffffffff, k0 + 0xfc); + // // After k0 comes the arguments, which is done by sceKernelStartThread(). + + // Memory::Write_U32(GetUID(), nt.initialStack); + // return true; + //} + + //void FreeStack() { + // if (currentStack.start != 0) { + // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name); + + // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { + // Memory::Memset(nt.initialStack, 0, nt.stack_size); + // } + + // if (nt.attr & PSP_THREAD_ATTR_KERNEL) { + // kernelMemory.Free(currentStack.start); + // } + // else { + // userMemory.Free(currentStack.start); + // } + // currentStack.start = 0; + // } + //} + + //bool PushExtendedStack(u32 size) { + // u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str()); + // if (stack == (u32)-1) + // return false; + + // pushed_stacks.push_back(currentStack); + // currentStack.start = stack; + // currentStack.end = stack + size; + // nt.initialStack = currentStack.start; + // nt.stack_size = currentStack.end - currentStack.start; + + // // We still drop the threadID at the bottom and fill it, but there's no k0. + // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); + // Memory::Write_U32(GetUID(), nt.initialStack); + // return true; + //} + + //bool PopExtendedStack() { + // if (pushed_stacks.size() == 0) { + // return false; + // } + // userMemory.Free(currentStack.start); + // currentStack = pushed_stacks.back(); + // pushed_stacks.pop_back(); + // nt.initialStack = currentStack.start; + // nt.stack_size = currentStack.end - currentStack.start; + // return true; + //} + + Thread() { + currentStack.start = 0; + } + + // Can't use a destructor since savestates will call that too. + //void Cleanup() { + // // Callbacks are automatically deleted when their owning thread is deleted. + // for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) + // kernelObjects.Destroy(*it); + + // if (pushed_stacks.size() != 0) + // { + // WARN_LOG(KERNEL, "Thread ended within an extended stack"); + // for (size_t i = 0; i < pushed_stacks.size(); ++i) + // userMemory.Free(pushed_stacks[i].start); + // } + // FreeStack(); + //} + + void setReturnValue(u32 retval); + void setReturnValue(u64 retval); + void resumeFromWait(); + //bool isWaitingFor(WaitType type, int id); + //int getWaitID(WaitType type); + ThreadWaitInfo getWaitInfo(); + + // Utils + //inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } + //inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } + //inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; } + //inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } + //inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } + + NativeThread nt; + + ThreadWaitInfo waitInfo; + UID moduleId; + + bool isProcessingCallbacks; + u32 currentMipscallId; + UID currentCallbackId; + + ThreadContext context; + + std::vector callbacks; + + std::list pending_calls; + + struct StackInfo { + u32 start; + u32 end; + }; + // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse. + // These are stacks that aren't "active" right now, but will pop off once the func returns. + std::vector pushed_stacks; + + StackInfo currentStack; + + // For thread end. + std::vector waiting_threads; + // Key is the callback id it was for, or if no callback, the thread id. + std::map paused_waits; +}; + +void __KernelThreadingInit() { +} + +void __KernelThreadingShutdown() { +} + +//const char *__KernelGetThreadName(UID threadID); +// +//void __KernelSaveContext(ThreadContext *ctx); +//void __KernelLoadContext(ThreadContext *ctx); + +//void __KernelSwitchContext(Thread *target, const char *reason); \ No newline at end of file -- cgit v1.2.3 From 3838d46b9022964617b93a45f3feab5052c3538b Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 13 May 2014 22:00:11 -0400 Subject: added a bunch of threading code, recycled from PPSSPP, with lots of hacks in for 3DS... doesn't really do much yet. Just a jumping off point --- src/core/hle/kernel/thread.cpp | 588 ++++++++++++++++++++++++++++++++++++----- src/core/hle/kernel/thread.h | 25 +- 2 files changed, 543 insertions(+), 70 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0ed35de83f..584276eecb 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -11,10 +11,212 @@ #include "common/common.h" +#include "core/core.h" +#include "core/mem_map.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -// Real CTR struct, don't change the fields. +struct ThreadQueueList { + // Number of queues (number of priority levels starting at 0.) + static const int NUM_QUEUES = 128; + // Initial number of threads a single queue can handle. + static const int INITIAL_CAPACITY = 32; + + struct Queue { + // Next ever-been-used queue (worse priority.) + Queue *next; + // First valid item in data. + int first; + // One after last valid item in data. + int end; + // A too-large array with room on the front and end. + UID *data; + // Size of data array. + int capacity; + }; + + ThreadQueueList() { + memset(queues, 0, sizeof(queues)); + first = invalid(); + } + + ~ThreadQueueList() { + for (int i = 0; i < NUM_QUEUES; ++i) { + if (queues[i].data != NULL) { + free(queues[i].data); + } + } + } + + // Only for debugging, returns priority level. + int contains(const UID uid) { + for (int i = 0; i < NUM_QUEUES; ++i) { + if (queues[i].data == NULL) { + continue; + } + Queue *cur = &queues[i]; + for (int j = cur->first; j < cur->end; ++j) { + if (cur->data[j] == uid) { + return i; + } + } + } + return -1; + } + + inline UID pop_first() { + Queue *cur = first; + while (cur != invalid()) { + if (cur->end - cur->first > 0) { + return cur->data[cur->first++]; + } + cur = cur->next; + } + + _dbg_assert_msg_(KERNEL, false, "ThreadQueueList should not be empty."); + return 0; + } + + inline UID pop_first_better(u32 priority) { + Queue *cur = first; + Queue *stop = &queues[priority]; + while (cur < stop) { + if (cur->end - cur->first > 0) { + return cur->data[cur->first++]; + } + cur = cur->next; + } + return 0; + } + + inline void push_front(u32 priority, const UID thread_id) { + Queue *cur = &queues[priority]; + cur->data[--cur->first] = thread_id; + if (cur->first == 0) { + rebalance(priority); + } + } + + inline void push_back(u32 priority, const UID thread_id) + { + Queue *cur = &queues[priority]; + cur->data[cur->end++] = thread_id; + if (cur->end == cur->capacity) { + rebalance(priority); + } + } + + inline void remove(u32 priority, const UID thread_id) { + Queue *cur = &queues[priority]; + _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up."); + + for (int i = cur->first; i < cur->end; ++i) { + if (cur->data[i] == thread_id) { + int remaining = --cur->end - i; + if (remaining > 0) { + memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(UID)); + } + return; + } + } + + // Wasn't there. + } + + inline void rotate(u32 priority) { + Queue *cur = &queues[priority]; + _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up."); + + if (cur->end - cur->first > 1) { + cur->data[cur->end++] = cur->data[cur->first++]; + if (cur->end == cur->capacity) { + rebalance(priority); + } + } + } + + inline void clear() { + for (int i = 0; i < NUM_QUEUES; ++i) { + if (queues[i].data != NULL) { + free(queues[i].data); + } + } + memset(queues, 0, sizeof(queues)); + first = invalid(); + } + + inline bool empty(u32 priority) const { + const Queue *cur = &queues[priority]; + return cur->first == cur->end; + } + + inline void prepare(u32 priority) { + Queue *cur = &queues[priority]; + if (cur->next == NULL) { + link(priority, INITIAL_CAPACITY); + } + } + +private: + Queue *invalid() const { + return (Queue *)-1; + } + + void link(u32 priority, int size) { + _dbg_assert_msg_(KERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once."); + + if (size <= INITIAL_CAPACITY) { + size = INITIAL_CAPACITY; + } else { + int goal = size; + size = INITIAL_CAPACITY; + while (size < goal) + size *= 2; + } + Queue *cur = &queues[priority]; + cur->data = (UID*)malloc(sizeof(UID)* size); + cur->capacity = size; + cur->first = size / 2; + cur->end = size / 2; + + for (int i = (int)priority - 1; i >= 0; --i) { + if (queues[i].next != NULL) { + cur->next = queues[i].next; + queues[i].next = cur; + return; + } + } + + cur->next = first; + first = cur; + } + + void rebalance(u32 priority) { + Queue *cur = &queues[priority]; + int size = cur->end - cur->first; + if (size >= cur->capacity - 2) { + UID* new_data = (UID*)realloc(cur->data, cur->capacity * 2 * sizeof(UID)); + if (new_data != NULL) { + cur->capacity *= 2; + cur->data = new_data; + } + } + + int newFirst = (cur->capacity - size) / 2; + if (newFirst != cur->first) { + memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(UID)); + cur->first = newFirst; + cur->end = newFirst + size; + } + } + + // The first queue that's ever been used. + Queue* first; + // The priority level queues of thread ids. + Queue queues[NUM_QUEUES]; +}; + +// Supposed to represent a real CTR struct... but not sure of the correct fields yet. struct NativeThread { //u32 Pointer to vtable //u32 Reference count @@ -25,6 +227,22 @@ struct NativeThread { // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000. //KThread* Previous ? (virtual address) //KThread* Next ? (virtual address) + + u32_le native_size; + char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; + + // Threading stuff + u32_le status; + u32_le entry_point; + u32_le initial_stack; + u32_le stack_top; + u32_le stack_size; + + u32_le arg; + u32_le processor_id; + + s32_le initial_priority; + s32_le current_priority; }; struct ThreadWaitInfo { @@ -52,42 +270,23 @@ public: //} //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } - //static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; } - //int GetIDType() const { return SCE_KERNEL_TMID_Thread; } - - //bool AllocateStack(u32 &stack_size) { - // FreeStack(); - - // bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0; - // if (nt.attr & PSP_THREAD_ATTR_KERNEL) - // { - // // Allocate stacks for kernel threads (idle) in kernel RAM - // currentStack.start = kernelMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); - // } - // else - // { - // currentStack.start = userMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str()); - // } - // if (currentStack.start == (u32)-1) - // { - // currentStack.start = 0; - // nt.initialStack = 0; - // ERROR_LOG(KERNEL, "Failed to allocate stack for thread"); - // return false; - // } - - // nt.initialStack = currentStack.start; - // nt.stack_size = stack_size; - // return true; - //} + static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; } + KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; } + + bool SetupStack(u32 stack_top, int stack_size) { + current_stack.start = stack_top; + nt.initial_stack = current_stack.start; + nt.stack_size = stack_size; + return true; + } //bool FillStack() { // // Fill the stack. // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { - // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); + // Memory::Memset(current_stack.start, 0xFF, nt.stack_size); // } - // context.r[MIPS_REG_SP] = currentStack.start + nt.stack_size; - // currentStack.end = context.r[MIPS_REG_SP]; + // context.r[MIPS_REG_SP] = current_stack.start + nt.stack_size; + // current_stack.end = context.r[MIPS_REG_SP]; // // The k0 section is 256 bytes at the top of the stack. // context.r[MIPS_REG_SP] -= 256; // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; @@ -104,7 +303,7 @@ public: //} //void FreeStack() { - // if (currentStack.start != 0) { + // if (current_stack.start != 0) { // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name); // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { @@ -112,12 +311,12 @@ public: // } // if (nt.attr & PSP_THREAD_ATTR_KERNEL) { - // kernelMemory.Free(currentStack.start); + // kernelMemory.Free(current_stack.start); // } // else { - // userMemory.Free(currentStack.start); + // userMemory.Free(current_stack.start); // } - // currentStack.start = 0; + // current_stack.start = 0; // } //} @@ -126,14 +325,14 @@ public: // if (stack == (u32)-1) // return false; - // pushed_stacks.push_back(currentStack); - // currentStack.start = stack; - // currentStack.end = stack + size; - // nt.initialStack = currentStack.start; - // nt.stack_size = currentStack.end - currentStack.start; + // pushed_stacks.push_back(current_stack); + // current_stack.start = stack; + // current_stack.end = stack + size; + // nt.initialStack = current_stack.start; + // nt.stack_size = current_stack.end - current_stack.start; - // // We still drop the threadID at the bottom and fill it, but there's no k0. - // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); + // // We still drop the thread_id at the bottom and fill it, but there's no k0. + // Memory::Memset(current_stack.start, 0xFF, nt.stack_size); // Memory::Write_U32(GetUID(), nt.initialStack); // return true; //} @@ -142,16 +341,16 @@ public: // if (pushed_stacks.size() == 0) { // return false; // } - // userMemory.Free(currentStack.start); - // currentStack = pushed_stacks.back(); + // userMemory.Free(current_stack.start); + // current_stack = pushed_stacks.back(); // pushed_stacks.pop_back(); - // nt.initialStack = currentStack.start; - // nt.stack_size = currentStack.end - currentStack.start; + // nt.initialStack = current_stack.start; + // nt.stack_size = current_stack.end - current_stack.start; // return true; //} Thread() { - currentStack.start = 0; + current_stack.start = 0; } // Can't use a destructor since savestates will call that too. @@ -177,20 +376,20 @@ public: ThreadWaitInfo getWaitInfo(); // Utils - //inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } - //inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } - //inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; } - //inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } - //inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } + inline bool IsRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } + inline bool IsStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } + inline bool IsReady() const { return (nt.status & THREADSTATUS_READY) != 0; } + inline bool IsWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } + inline bool IsSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } NativeThread nt; ThreadWaitInfo waitInfo; UID moduleId; - bool isProcessingCallbacks; - u32 currentMipscallId; - UID currentCallbackId; + //bool isProcessingCallbacks; + //u32 currentMipscallId; + //UID currentCallbackId; ThreadContext context; @@ -206,7 +405,7 @@ public: // These are stacks that aren't "active" right now, but will pop off once the func returns. std::vector pushed_stacks; - StackInfo currentStack; + StackInfo current_stack; // For thread end. std::vector waiting_threads; @@ -214,15 +413,276 @@ public: std::map paused_waits; }; -void __KernelThreadingInit() { +void ThreadContext::reset() { + for (int i = 0; i < 16; i++) { + reg[i] = 0; + } + reg[13] = Memory::SCRATCHPAD_VADDR_END; + cpsr = 0; } -void __KernelThreadingShutdown() { +// Lists all thread ids that aren't deleted/etc. +std::vector g_thread_queue; + +// Lists only ready thread ids +ThreadQueueList g_thread_ready_queue; + +UID g_current_thread; +Thread* g_current_thread_ptr; +const char *g_hle_current_thread_name = NULL; + +Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, + u32 entrypoint, u32 arg, u32 stack_top, u32 processor_id, int stack_size) { + + Thread *t = new Thread; + id = g_kernel_objects.Create(t); + + g_thread_queue.push_back(id); + g_thread_ready_queue.prepare(priority); + + memset(&t->nt, 0xCD, sizeof(t->nt)); + + t->nt.entry_point = entrypoint; + t->nt.native_size = sizeof(t->nt); + t->nt.initial_priority = t->nt.current_priority = priority; + t->nt.status = THREADSTATUS_DORMANT; + t->nt.initial_stack = t->nt.stack_top = stack_top; + t->nt.stack_size = stack_size; + t->nt.processor_id = processor_id; + + strncpy(t->nt.name, name, KERNELOBJECT_MAX_NAME_LENGTH); + t->nt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; + + t->nt.stack_size = stack_size; + t->SetupStack(stack_top, stack_size); + + return t; +} + +void __KernelResetThread(Thread *t, int lowest_priority) { + t->context.reset(); + t->context.pc = t->nt.entry_point; + + // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd... + if (t->nt.current_priority < lowest_priority) + t->nt.current_priority = t->nt.initial_priority; + + //t->nt.wait_type = WAITTYPE_NONE; + //t->nt.wait_id = 0; + memset(&t->waitInfo, 0, sizeof(t->waitInfo)); + + //t->nt.exitStatus = SCE_KERNEL_ERROR_NOT_DORMANT; + //t->isProcessingCallbacks = false; + //t->currentCallbackId = 0; + //t->currentMipscallId = 0; + //t->pendingMipsCalls.clear(); + + //t->context.r[MIPS_REG_RA] = threadReturnHackAddr; //hack! TODO fix + // TODO: Not sure if it's reset here, but this makes sense. + //t->context.r[MIPS_REG_GP] = t->nt.gpreg; + //t->FillStack(); + + //if (!t->waitingThreads.empty()) + // ERROR_LOG(KERNEL, "Resetting thread with threads waiting on end?"); +} + + +inline Thread *__GetCurrentThread() { + return g_current_thread_ptr; +} + +inline void __SetCurrentThread(Thread *thread, UID thread_id, const char *name) { + g_current_thread = thread_id; + g_current_thread_ptr = thread; + g_hle_current_thread_name = name; +} + +// TODO: Use __KernelChangeThreadState instead? It has other affects... +void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready) { + // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc. + _dbg_assert_msg_(KERNEL, thread->GetUID() == thread_id, "Incorrect thread_id"); + int prio = thread->nt.current_priority; + + if (thread->IsReady()) { + if (!ready) + g_thread_ready_queue.remove(prio, thread_id); + } else if (ready) { + if (thread->IsRunning()) { + g_thread_ready_queue.push_front(prio, thread_id); + } else { + g_thread_ready_queue.push_back(prio, thread_id); + } + thread->nt.status = THREADSTATUS_READY; + } +} + +void __KernelChangeReadyState(UID thread_id, bool ready) { + u32 error; + Thread *thread = g_kernel_objects.Get(thread_id, error); + if (thread) { + __KernelChangeReadyState(thread, thread_id, ready); + } else { + WARN_LOG(KERNEL, "Trying to change the ready state of an unknown thread?"); + } +} + +// Returns NULL if the current thread is fine. +Thread* __KernelNextThread() { + UID bestThread; + + // If the current thread is running, it's a valid candidate. + Thread *cur = __GetCurrentThread(); + if (cur && cur->IsRunning()) { + bestThread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority); + if (bestThread != 0) { + __KernelChangeReadyState(cur, g_current_thread, true); + } + } else { + bestThread = g_thread_ready_queue.pop_first(); + } + + // Assume g_thread_ready_queue has not become corrupt. + if (bestThread != 0) { + return g_kernel_objects.GetFast(bestThread); + } else { + return NULL; + } +} + +// Saves the current CPU context +void __KernelSaveContext(ThreadContext *ctx) { + ctx->reg[0] = Core::g_app_core->GetReg(0); + ctx->reg[1] = Core::g_app_core->GetReg(1); + ctx->reg[2] = Core::g_app_core->GetReg(2); + ctx->reg[3] = Core::g_app_core->GetReg(3); + ctx->reg[4] = Core::g_app_core->GetReg(4); + ctx->reg[5] = Core::g_app_core->GetReg(5); + ctx->reg[6] = Core::g_app_core->GetReg(6); + ctx->reg[7] = Core::g_app_core->GetReg(7); + ctx->reg[8] = Core::g_app_core->GetReg(8); + ctx->reg[9] = Core::g_app_core->GetReg(9); + ctx->reg[10] = Core::g_app_core->GetReg(10); + ctx->reg[11] = Core::g_app_core->GetReg(11); + ctx->reg[12] = Core::g_app_core->GetReg(12); + ctx->reg[13] = Core::g_app_core->GetReg(13); + ctx->reg[14] = Core::g_app_core->GetReg(14); + ctx->reg[15] = Core::g_app_core->GetReg(15); + ctx->pc = Core::g_app_core->GetPC(); + ctx->cpsr = Core::g_app_core->GetCPSR(); +} + +// Loads a CPU context +void __KernelLoadContext(ThreadContext *ctx) { + Core::g_app_core->SetReg(0, ctx->reg[0]); + Core::g_app_core->SetReg(1, ctx->reg[1]); + Core::g_app_core->SetReg(2, ctx->reg[2]); + Core::g_app_core->SetReg(3, ctx->reg[3]); + Core::g_app_core->SetReg(4, ctx->reg[4]); + Core::g_app_core->SetReg(5, ctx->reg[5]); + Core::g_app_core->SetReg(6, ctx->reg[6]); + Core::g_app_core->SetReg(7, ctx->reg[7]); + Core::g_app_core->SetReg(8, ctx->reg[8]); + Core::g_app_core->SetReg(9, ctx->reg[9]); + Core::g_app_core->SetReg(10, ctx->reg[10]); + Core::g_app_core->SetReg(11, ctx->reg[11]); + Core::g_app_core->SetReg(12, ctx->reg[12]); + Core::g_app_core->SetReg(13, ctx->reg[13]); + Core::g_app_core->SetReg(14, ctx->reg[14]); + Core::g_app_core->SetReg(15, ctx->reg[15]); + Core::g_app_core->SetPC(ctx->pc); + Core::g_app_core->SetCPSR(ctx->cpsr); +} + +void __KernelSwitchContext(Thread *target, const char *reason) { + u32 oldPC = 0; + UID oldUID = 0; + const char *oldName = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)"; + + Thread *cur = __GetCurrentThread(); + if (cur) { // It might just have been deleted. + __KernelSaveContext(&cur->context); + oldPC = Core::g_app_core->GetPC(); + oldUID = cur->GetUID(); + + // Normally this is taken care of in __KernelNextThread(). + if (cur->IsRunning()) + __KernelChangeReadyState(cur, oldUID, true); + } + + if (target) { + __SetCurrentThread(target, target->GetUID(), target->nt.name); + __KernelChangeReadyState(target, g_current_thread, false); + target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; + + __KernelLoadContext(&target->context); + } else { + __SetCurrentThread(NULL, 0, NULL); + } + +#if DEBUG_LEVEL <= MAX_LOGLEVEL || DEBUG_LOG == NOTICE_LOG + //bool fromIdle = oldUID == threadIdleID[0] || oldUID == threadIdleID[1]; + //bool toIdle = currentThread == threadIdleID[0] || currentThread == threadIdleID[1]; + //if (!(fromIdle && toIdle)) + //{ + // u64 nowCycles = CoreTiming::GetTicks(); + // s64 consumedCycles = nowCycles - lastSwitchCycles; + // lastSwitchCycles = nowCycles; + + // DEBUG_LOG(SCEKERNEL, "Context switch: %s -> %s (%i->%i, pc: %08x->%08x, %s) +%lldus", + // oldName, hleCurrentThreadName, + // oldUID, currentThread, + // oldPC, currentMIPS->pc, + // reason, + // cyclesToUs(consumedCycles)); + //} +#endif + + if (target) { + //// No longer waiting. + //target->nt.waitType = WAITTYPE_NONE; + //target->nt.waitID = 0; + + //__KernelExecutePendingARMCalls(target, true); + } +} + +UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) { + UID id; + + Thread *thread = __KernelCreateThread(id, module_id, "root", prio, Core::g_app_core->GetPC(), + arg, Memory::SCRATCHPAD_VADDR_END, 0xFFFFFFFE, stack_size=stack_size); + + if (thread->current_stack.start == 0) { + ERROR_LOG(KERNEL, "Unable to allocate stack for root thread."); + } + __KernelResetThread(thread, 0); + + Thread *prev_thread = __GetCurrentThread(); + if (prev_thread && prev_thread->IsRunning()) + __KernelChangeReadyState(g_current_thread, true); + __SetCurrentThread(thread, id, "root"); + thread->nt.status = THREADSTATUS_RUNNING; // do not schedule + + strcpy(thread->nt.name, "root"); + + __KernelLoadContext(&thread->context); + + // NOTE(bunnei): Not sure this is really correct, ignore args for now... + //Core::g_app_core->SetReg(0, args); + //Core::g_app_core->SetReg(13, (args + 0xf) & ~0xf); // Setup SP - probably not correct + //u32 location = Core::g_app_core->GetReg(13); // SP + //Core::g_app_core->SetReg(1, location); + + //if (argp) + // Memory::Memcpy(location, argp, args); + //// Let's assume same as starting a new thread, 64 bytes for safety/kernel. + //Core::g_app_core->SetReg(13, Core::g_app_core->GetReg(13) - 64); + + return id; } -//const char *__KernelGetThreadName(UID threadID); -// -//void __KernelSaveContext(ThreadContext *ctx); -//void __KernelLoadContext(ThreadContext *ctx); +void __KernelThreadingInit() { +} -//void __KernelSwitchContext(Thread *target, const char *reason); \ No newline at end of file +void __KernelThreadingShutdown() { +} diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c3cdca31f4..38180cb9bf 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -7,12 +7,12 @@ #include "common/common_types.h" enum ThreadStatus { - THREADSTATUS_RUNNING = 1, - THREADSTATUS_READY = 2, - THREADSTATUS_WAIT = 4, - THREADSTATUS_SUSPEND = 8, - THREADSTATUS_DORMANT = 16, - THREADSTATUS_DEAD = 32, + THREADSTATUS_RUNNING = 1, + THREADSTATUS_READY = 2, + THREADSTATUS_WAIT = 4, + THREADSTATUS_SUSPEND = 8, + THREADSTATUS_DORMANT = 16, + THREADSTATUS_DEAD = 32, THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND }; @@ -25,6 +25,19 @@ struct ThreadContext { u32 pc; }; +class Thread; + +Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, u32 entrypoint, + u32 arg, u32 stack_top, u32 processor_id, int stack_size=0x4000); +void __KernelResetThread(Thread *t, int lowest_priority); +void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready); +void __KernelChangeReadyState(UID thread_id, bool ready); +Thread* __KernelNextThread(); +void __KernelSaveContext(ThreadContext *ctx); +void __KernelLoadContext(ThreadContext *ctx); +void __KernelSwitchContext(Thread *target, const char *reason); +UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size=0x4000); + void __KernelThreadingInit(); void __KernelThreadingShutdown(); -- cgit v1.2.3 From 7d078189daec2db8a465a401b6867739fea5043d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 13 May 2014 22:29:31 -0400 Subject: various cleanups / remove unused code --- src/core/hle/kernel/thread.cpp | 93 +++++++++++++----------------------------- src/core/hle/kernel/thread.h | 1 + 2 files changed, 29 insertions(+), 65 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 584276eecb..95ef2c173d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -427,10 +427,11 @@ std::vector g_thread_queue; // Lists only ready thread ids ThreadQueueList g_thread_ready_queue; -UID g_current_thread; -Thread* g_current_thread_ptr; -const char *g_hle_current_thread_name = NULL; +UID g_current_thread = 0; +Thread* g_current_thread_ptr = NULL; +const char* g_hle_current_thread_name = NULL; +/// Creates a new thread Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, u32 entrypoint, u32 arg, u32 stack_top, u32 processor_id, int stack_size) { @@ -459,38 +460,25 @@ Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 prior return t; } +/// Resets the specified thread back to initial calling state void __KernelResetThread(Thread *t, int lowest_priority) { t->context.reset(); t->context.pc = t->nt.entry_point; // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd... - if (t->nt.current_priority < lowest_priority) + if (t->nt.current_priority < lowest_priority) { t->nt.current_priority = t->nt.initial_priority; + } - //t->nt.wait_type = WAITTYPE_NONE; - //t->nt.wait_id = 0; memset(&t->waitInfo, 0, sizeof(t->waitInfo)); - - //t->nt.exitStatus = SCE_KERNEL_ERROR_NOT_DORMANT; - //t->isProcessingCallbacks = false; - //t->currentCallbackId = 0; - //t->currentMipscallId = 0; - //t->pendingMipsCalls.clear(); - - //t->context.r[MIPS_REG_RA] = threadReturnHackAddr; //hack! TODO fix - // TODO: Not sure if it's reset here, but this makes sense. - //t->context.r[MIPS_REG_GP] = t->nt.gpreg; - //t->FillStack(); - - //if (!t->waitingThreads.empty()) - // ERROR_LOG(KERNEL, "Resetting thread with threads waiting on end?"); } - +/// Returns the current executing thread inline Thread *__GetCurrentThread() { return g_current_thread_ptr; } +/// Sets the current executing thread inline void __SetCurrentThread(Thread *thread, UID thread_id, const char *name) { g_current_thread = thread_id; g_current_thread_ptr = thread; @@ -526,30 +514,29 @@ void __KernelChangeReadyState(UID thread_id, bool ready) { } } -// Returns NULL if the current thread is fine. +/// Returns NULL if the current thread is fine. Thread* __KernelNextThread() { - UID bestThread; + UID best_thread; // If the current thread is running, it's a valid candidate. Thread *cur = __GetCurrentThread(); if (cur && cur->IsRunning()) { - bestThread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority); - if (bestThread != 0) { + best_thread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority); + if (best_thread != 0) { __KernelChangeReadyState(cur, g_current_thread, true); } } else { - bestThread = g_thread_ready_queue.pop_first(); + best_thread = g_thread_ready_queue.pop_first(); } - // Assume g_thread_ready_queue has not become corrupt. - if (bestThread != 0) { - return g_kernel_objects.GetFast(bestThread); + if (best_thread != 0) { + return g_kernel_objects.GetFast(best_thread); } else { return NULL; } } -// Saves the current CPU context +/// Saves the current CPU context void __KernelSaveContext(ThreadContext *ctx) { ctx->reg[0] = Core::g_app_core->GetReg(0); ctx->reg[1] = Core::g_app_core->GetReg(1); @@ -571,7 +558,7 @@ void __KernelSaveContext(ThreadContext *ctx) { ctx->cpsr = Core::g_app_core->GetCPSR(); } -// Loads a CPU context +/// Loads a CPU context void __KernelLoadContext(ThreadContext *ctx) { Core::g_app_core->SetReg(0, ctx->reg[0]); Core::g_app_core->SetReg(1, ctx->reg[1]); @@ -593,59 +580,35 @@ void __KernelLoadContext(ThreadContext *ctx) { Core::g_app_core->SetCPSR(ctx->cpsr); } +/// Switches thread context void __KernelSwitchContext(Thread *target, const char *reason) { - u32 oldPC = 0; - UID oldUID = 0; - const char *oldName = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)"; - + u32 old_pc = 0; + UID old_uid = 0; + const char *old_name = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)"; Thread *cur = __GetCurrentThread(); + if (cur) { // It might just have been deleted. __KernelSaveContext(&cur->context); - oldPC = Core::g_app_core->GetPC(); - oldUID = cur->GetUID(); + old_pc = Core::g_app_core->GetPC(); + old_uid = cur->GetUID(); // Normally this is taken care of in __KernelNextThread(). if (cur->IsRunning()) - __KernelChangeReadyState(cur, oldUID, true); + __KernelChangeReadyState(cur, old_uid, true); } - if (target) { __SetCurrentThread(target, target->GetUID(), target->nt.name); __KernelChangeReadyState(target, g_current_thread, false); + target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; __KernelLoadContext(&target->context); } else { __SetCurrentThread(NULL, 0, NULL); } - -#if DEBUG_LEVEL <= MAX_LOGLEVEL || DEBUG_LOG == NOTICE_LOG - //bool fromIdle = oldUID == threadIdleID[0] || oldUID == threadIdleID[1]; - //bool toIdle = currentThread == threadIdleID[0] || currentThread == threadIdleID[1]; - //if (!(fromIdle && toIdle)) - //{ - // u64 nowCycles = CoreTiming::GetTicks(); - // s64 consumedCycles = nowCycles - lastSwitchCycles; - // lastSwitchCycles = nowCycles; - - // DEBUG_LOG(SCEKERNEL, "Context switch: %s -> %s (%i->%i, pc: %08x->%08x, %s) +%lldus", - // oldName, hleCurrentThreadName, - // oldUID, currentThread, - // oldPC, currentMIPS->pc, - // reason, - // cyclesToUs(consumedCycles)); - //} -#endif - - if (target) { - //// No longer waiting. - //target->nt.waitType = WAITTYPE_NONE; - //target->nt.waitID = 0; - - //__KernelExecutePendingARMCalls(target, true); - } } +/// Sets up the root (primary) thread of execution UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) { UID id; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 38180cb9bf..1731248cc2 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -5,6 +5,7 @@ #pragma once #include "common/common_types.h" +#include "core/hle/kernel/kernel.h" enum ThreadStatus { THREADSTATUS_RUNNING = 1, -- cgit v1.2.3 From 0de78eb3c4407cfedb8779422d96b7ee73fc19ed Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 13 May 2014 23:18:28 -0400 Subject: fixed thread reset to not set stack address --- src/core/hle/kernel/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 95ef2c173d..c59d2a6893 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -417,7 +417,6 @@ void ThreadContext::reset() { for (int i = 0; i < 16; i++) { reg[i] = 0; } - reg[13] = Memory::SCRATCHPAD_VADDR_END; cpsr = 0; } @@ -464,6 +463,7 @@ Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 prior void __KernelResetThread(Thread *t, int lowest_priority) { t->context.reset(); t->context.pc = t->nt.entry_point; + t->context.reg[13] = t->nt.initial_stack; // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd... if (t->nt.current_priority < lowest_priority) { -- cgit v1.2.3 From b99a5da65b76ce16e40fe05feb786aac11931904 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 May 2014 20:50:30 -0400 Subject: - added helper function for __KernelCreateThread - added __KernelSwitchToThread for enabling a thread - added __KernelRotateThreadReadyQueue --- src/core/hle/kernel/thread.cpp | 74 +++++++++++++++++++++++++++++++++++++++--- src/core/hle/kernel/thread.h | 6 ++++ 2 files changed, 76 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index c59d2a6893..b6d02aa120 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,8 @@ #include "core/core.h" #include "core/mem_map.h" +#include "core/hle/hle.h" +#include "core/hle/syscall.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" @@ -357,7 +359,7 @@ public: //void Cleanup() { // // Callbacks are automatically deleted when their owning thread is deleted. // for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) - // kernelObjects.Destroy(*it); + // g_kernel_objects.Destroy(*it); // if (pushed_stacks.size() != 0) // { @@ -432,7 +434,7 @@ const char* g_hle_current_thread_name = NULL; /// Creates a new thread Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, - u32 entrypoint, u32 arg, u32 stack_top, u32 processor_id, int stack_size) { + u32 entry_point, u32 arg, u32 stack_top, u32 processor_id, int stack_size) { Thread *t = new Thread; id = g_kernel_objects.Create(t); @@ -442,7 +444,7 @@ Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 prior memset(&t->nt, 0xCD, sizeof(t->nt)); - t->nt.entry_point = entrypoint; + t->nt.entry_point = entry_point; t->nt.native_size = sizeof(t->nt); t->nt.initial_priority = t->nt.current_priority = priority; t->nt.status = THREADSTATUS_DORMANT; @@ -459,6 +461,18 @@ Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 prior return t; } +UID __KernelCreateThread(UID module_id, const char* name, u32 priority, u32 entry_point, u32 arg, + u32 stack_top, u32 processor_id, int stack_size) { + UID id; + __KernelCreateThread(id, module_id, name, priority, entry_point, arg, stack_top, processor_id, + stack_size); + + HLE::EatCycles(32000); + HLE::ReSchedule("thread created"); + + return id; +} + /// Resets the specified thread back to initial calling state void __KernelResetThread(Thread *t, int lowest_priority) { t->context.reset(); @@ -608,6 +622,31 @@ void __KernelSwitchContext(Thread *target, const char *reason) { } } +bool __KernelSwitchToThread(UID thread_id, const char *reason) { + if (!reason) { + reason = "switch to thread"; + } + if (g_current_thread == thread_id) { + return false; + } + u32 error; + Thread *t = g_kernel_objects.Get(thread_id, error); + if (!t) { + ERROR_LOG(KERNEL, "__KernelSwitchToThread: %x doesn't exist", thread_id); + HLE::ReSchedule("switch to deleted thread"); + } else if (t->IsReady() || t->IsRunning()) { + Thread *current = __GetCurrentThread(); + if (current && current->IsRunning()) { + __KernelChangeReadyState(current, g_current_thread, true); + } + __KernelSwitchContext(t, reason); + return true; + } else { + HLE::ReSchedule("switch to waiting thread"); + } + return false; +} + /// Sets up the root (primary) thread of execution UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) { UID id; @@ -633,7 +672,7 @@ UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) { // NOTE(bunnei): Not sure this is really correct, ignore args for now... //Core::g_app_core->SetReg(0, args); //Core::g_app_core->SetReg(13, (args + 0xf) & ~0xf); // Setup SP - probably not correct - //u32 location = Core::g_app_core->GetReg(13); // SP + //u32 location = Core::g_app_core->GetReg(13); // SP //Core::g_app_core->SetReg(1, location); //if (argp) @@ -644,6 +683,33 @@ UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) { return id; } +int __KernelRotateThreadReadyQueue(int priority) { + Thread *cur = __GetCurrentThread(); + + // 0 is special, it means "my current priority." + if (priority == 0) { + priority = cur->nt.current_priority; + } + //if (priority <= 0x07 || priority > 0x77) + // return SCE_KERNEL_ERROR_ILLEGAL_PRIORITY; + + if (!g_thread_ready_queue.empty(priority)) { + // In other words, yield to everyone else. + if (cur->nt.current_priority == priority) { + g_thread_ready_queue.push_back(priority, g_current_thread); + cur->nt.status = (cur->nt.status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; + + // Yield the next thread of this priority to all other threads of same priority. + } else { + g_thread_ready_queue.rotate(priority); + } + } + HLE::EatCycles(250); + HLE::ReSchedule("rotatethreadreadyqueue"); + + return 0; +} + void __KernelThreadingInit() { } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 1731248cc2..05468fb2e0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -30,6 +30,10 @@ class Thread; Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, u32 entrypoint, u32 arg, u32 stack_top, u32 processor_id, int stack_size=0x4000); + +UID __KernelCreateThread(UID module_id, const char* name, u32 priority, u32 entry_point, u32 arg, + u32 stack_top, u32 processor_id, int stack_size=0x4000); + void __KernelResetThread(Thread *t, int lowest_priority); void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready); void __KernelChangeReadyState(UID thread_id, bool ready); @@ -37,7 +41,9 @@ Thread* __KernelNextThread(); void __KernelSaveContext(ThreadContext *ctx); void __KernelLoadContext(ThreadContext *ctx); void __KernelSwitchContext(Thread *target, const char *reason); +bool __KernelSwitchToThread(UID thread_id, const char *reason); UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size=0x4000); +int __KernelRotateThreadReadyQueue(int priority=0); void __KernelThreadingInit(); void __KernelThreadingShutdown(); -- cgit v1.2.3 From 940330c6e12b3eefb9fb035f75f4b090c969cb75 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 15 May 2014 18:27:08 -0400 Subject: completely gutted/refactored threading code to be simpler --- src/core/hle/kernel/thread.cpp | 844 +++++++++++------------------------------ src/core/hle/kernel/thread.h | 44 +-- 2 files changed, 230 insertions(+), 658 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b6d02aa120..833a1b4bad 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -10,6 +10,7 @@ #include #include "common/common.h" +#include "common/thread_queue_list.h" #include "core/core.h" #include "core/mem_map.h" @@ -18,698 +19,309 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -struct ThreadQueueList { - // Number of queues (number of priority levels starting at 0.) - static const int NUM_QUEUES = 128; - // Initial number of threads a single queue can handle. - static const int INITIAL_CAPACITY = 32; - - struct Queue { - // Next ever-been-used queue (worse priority.) - Queue *next; - // First valid item in data. - int first; - // One after last valid item in data. - int end; - // A too-large array with room on the front and end. - UID *data; - // Size of data array. - int capacity; - }; - - ThreadQueueList() { - memset(queues, 0, sizeof(queues)); - first = invalid(); - } - - ~ThreadQueueList() { - for (int i = 0; i < NUM_QUEUES; ++i) { - if (queues[i].data != NULL) { - free(queues[i].data); - } - } - } - - // Only for debugging, returns priority level. - int contains(const UID uid) { - for (int i = 0; i < NUM_QUEUES; ++i) { - if (queues[i].data == NULL) { - continue; - } - Queue *cur = &queues[i]; - for (int j = cur->first; j < cur->end; ++j) { - if (cur->data[j] == uid) { - return i; - } - } - } - return -1; - } - - inline UID pop_first() { - Queue *cur = first; - while (cur != invalid()) { - if (cur->end - cur->first > 0) { - return cur->data[cur->first++]; - } - cur = cur->next; - } - - _dbg_assert_msg_(KERNEL, false, "ThreadQueueList should not be empty."); - return 0; - } - - inline UID pop_first_better(u32 priority) { - Queue *cur = first; - Queue *stop = &queues[priority]; - while (cur < stop) { - if (cur->end - cur->first > 0) { - return cur->data[cur->first++]; - } - cur = cur->next; - } - return 0; - } - - inline void push_front(u32 priority, const UID thread_id) { - Queue *cur = &queues[priority]; - cur->data[--cur->first] = thread_id; - if (cur->first == 0) { - rebalance(priority); - } - } - - inline void push_back(u32 priority, const UID thread_id) - { - Queue *cur = &queues[priority]; - cur->data[cur->end++] = thread_id; - if (cur->end == cur->capacity) { - rebalance(priority); - } - } - - inline void remove(u32 priority, const UID thread_id) { - Queue *cur = &queues[priority]; - _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up."); - - for (int i = cur->first; i < cur->end; ++i) { - if (cur->data[i] == thread_id) { - int remaining = --cur->end - i; - if (remaining > 0) { - memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(UID)); - } - return; - } - } - - // Wasn't there. - } - - inline void rotate(u32 priority) { - Queue *cur = &queues[priority]; - _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up."); - - if (cur->end - cur->first > 1) { - cur->data[cur->end++] = cur->data[cur->first++]; - if (cur->end == cur->capacity) { - rebalance(priority); - } - } - } - - inline void clear() { - for (int i = 0; i < NUM_QUEUES; ++i) { - if (queues[i].data != NULL) { - free(queues[i].data); - } - } - memset(queues, 0, sizeof(queues)); - first = invalid(); - } - - inline bool empty(u32 priority) const { - const Queue *cur = &queues[priority]; - return cur->first == cur->end; - } - - inline void prepare(u32 priority) { - Queue *cur = &queues[priority]; - if (cur->next == NULL) { - link(priority, INITIAL_CAPACITY); - } - } - -private: - Queue *invalid() const { - return (Queue *)-1; - } - - void link(u32 priority, int size) { - _dbg_assert_msg_(KERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once."); - - if (size <= INITIAL_CAPACITY) { - size = INITIAL_CAPACITY; - } else { - int goal = size; - size = INITIAL_CAPACITY; - while (size < goal) - size *= 2; - } - Queue *cur = &queues[priority]; - cur->data = (UID*)malloc(sizeof(UID)* size); - cur->capacity = size; - cur->first = size / 2; - cur->end = size / 2; - - for (int i = (int)priority - 1; i >= 0; --i) { - if (queues[i].next != NULL) { - cur->next = queues[i].next; - queues[i].next = cur; - return; - } - } - - cur->next = first; - first = cur; - } - - void rebalance(u32 priority) { - Queue *cur = &queues[priority]; - int size = cur->end - cur->first; - if (size >= cur->capacity - 2) { - UID* new_data = (UID*)realloc(cur->data, cur->capacity * 2 * sizeof(UID)); - if (new_data != NULL) { - cur->capacity *= 2; - cur->data = new_data; - } - } +// Enums - int newFirst = (cur->capacity - size) / 2; - if (newFirst != cur->first) { - memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(UID)); - cur->first = newFirst; - cur->end = newFirst + size; - } - } +enum ThreadPriority { + THREADPRIO_HIGHEST = 0, + THREADPRIO_DEFAULT = 16, + THREADPRIO_LOWEST = 31, +}; - // The first queue that's ever been used. - Queue* first; - // The priority level queues of thread ids. - Queue queues[NUM_QUEUES]; +enum ThreadStatus { + THREADSTATUS_RUNNING = 1, + THREADSTATUS_READY = 2, + THREADSTATUS_WAIT = 4, + THREADSTATUS_SUSPEND = 8, + THREADSTATUS_DORMANT = 16, + THREADSTATUS_DEAD = 32, + THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND }; -// Supposed to represent a real CTR struct... but not sure of the correct fields yet. -struct NativeThread { - //u32 Pointer to vtable - //u32 Reference count - //KProcess* Process the thread belongs to (virtual address) - //u32 Thread id - //u32* ptr = *(KThread+0x8C) - 0xB0 - //u32* End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus, - // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000. - //KThread* Previous ? (virtual address) - //KThread* Next ? (virtual address) - - u32_le native_size; - char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; - - // Threading stuff - u32_le status; - u32_le entry_point; - u32_le initial_stack; - u32_le stack_top; - u32_le stack_size; +enum WaitType { + WAITTYPE_NONE, + WAITTYPE_SLEEP, + WAITTYPE_SEMA, + WAITTYPE_EVENTFLAG, + WAITTYPE_THREADEND, + WAITTYPE_VBLANK, + WAITTYPE_MUTEX, + WAITTYPE_SYNCH, - u32_le arg; - u32_le processor_id; - - s32_le initial_priority; - s32_le current_priority; + NUM_WAITTYPES }; -struct ThreadWaitInfo { - u32 wait_value; - u32 timeout_ptr; -}; +typedef s32 Handle; class Thread : public KernelObject { public: - /*const char *GetName() { return nt.name; }*/ + + const char *GetName() { return name; } const char *GetTypeName() { return "Thread"; } - //void GetQuickInfo(char *ptr, int size) - //{ - // sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )", - // context.pc, context.r[13], // 13 is stack pointer - // (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "", - // (nt.status & THREADSTATUS_READY) ? "READY" : "", - // (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "", - // (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "", - // (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "", - // (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "", - // nt.waitType, - // nt.waitID, - // waitInfo.waitValue); - //} - - //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } + static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; } KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; } - bool SetupStack(u32 stack_top, int stack_size) { - current_stack.start = stack_top; - nt.initial_stack = current_stack.start; - nt.stack_size = stack_size; - return true; - } - - //bool FillStack() { - // // Fill the stack. - // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { - // Memory::Memset(current_stack.start, 0xFF, nt.stack_size); - // } - // context.r[MIPS_REG_SP] = current_stack.start + nt.stack_size; - // current_stack.end = context.r[MIPS_REG_SP]; - // // The k0 section is 256 bytes at the top of the stack. - // context.r[MIPS_REG_SP] -= 256; - // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; - // u32 k0 = context.r[MIPS_REG_K0]; - // Memory::Memset(k0, 0, 0x100); - // Memory::Write_U32(GetUID(), k0 + 0xc0); - // Memory::Write_U32(nt.initialStack, k0 + 0xc8); - // Memory::Write_U32(0xffffffff, k0 + 0xf8); - // Memory::Write_U32(0xffffffff, k0 + 0xfc); - // // After k0 comes the arguments, which is done by sceKernelStartThread(). - - // Memory::Write_U32(GetUID(), nt.initialStack); - // return true; - //} - - //void FreeStack() { - // if (current_stack.start != 0) { - // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name); - - // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { - // Memory::Memset(nt.initialStack, 0, nt.stack_size); - // } - - // if (nt.attr & PSP_THREAD_ATTR_KERNEL) { - // kernelMemory.Free(current_stack.start); - // } - // else { - // userMemory.Free(current_stack.start); - // } - // current_stack.start = 0; - // } - //} - - //bool PushExtendedStack(u32 size) { - // u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str()); - // if (stack == (u32)-1) - // return false; - - // pushed_stacks.push_back(current_stack); - // current_stack.start = stack; - // current_stack.end = stack + size; - // nt.initialStack = current_stack.start; - // nt.stack_size = current_stack.end - current_stack.start; - - // // We still drop the thread_id at the bottom and fill it, but there's no k0. - // Memory::Memset(current_stack.start, 0xFF, nt.stack_size); - // Memory::Write_U32(GetUID(), nt.initialStack); - // return true; - //} - - //bool PopExtendedStack() { - // if (pushed_stacks.size() == 0) { - // return false; - // } - // userMemory.Free(current_stack.start); - // current_stack = pushed_stacks.back(); - // pushed_stacks.pop_back(); - // nt.initialStack = current_stack.start; - // nt.stack_size = current_stack.end - current_stack.start; - // return true; - //} - - Thread() { - current_stack.start = 0; - } - - // Can't use a destructor since savestates will call that too. - //void Cleanup() { - // // Callbacks are automatically deleted when their owning thread is deleted. - // for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) - // g_kernel_objects.Destroy(*it); - - // if (pushed_stacks.size() != 0) - // { - // WARN_LOG(KERNEL, "Thread ended within an extended stack"); - // for (size_t i = 0; i < pushed_stacks.size(); ++i) - // userMemory.Free(pushed_stacks[i].start); - // } - // FreeStack(); - //} - - void setReturnValue(u32 retval); - void setReturnValue(u64 retval); - void resumeFromWait(); - //bool isWaitingFor(WaitType type, int id); - //int getWaitID(WaitType type); - ThreadWaitInfo getWaitInfo(); - - // Utils - inline bool IsRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } - inline bool IsStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } - inline bool IsReady() const { return (nt.status & THREADSTATUS_READY) != 0; } - inline bool IsWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } - inline bool IsSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } - - NativeThread nt; - - ThreadWaitInfo waitInfo; - UID moduleId; - - //bool isProcessingCallbacks; - //u32 currentMipscallId; - //UID currentCallbackId; + inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } + inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } + inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } + inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } + inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } ThreadContext context; - std::vector callbacks; + u32 status; + u32 entry_point; + u32 stack_top; + u32 stack_size; - std::list pending_calls; + s32 initial_priority; + s32 current_priority; - struct StackInfo { - u32 start; - u32 end; - }; - // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse. - // These are stacks that aren't "active" right now, but will pop off once the func returns. - std::vector pushed_stacks; + s32 processor_id; - StackInfo current_stack; + WaitType wait_type; - // For thread end. - std::vector waiting_threads; - // Key is the callback id it was for, or if no callback, the thread id. - std::map paused_waits; + char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; }; -void ThreadContext::reset() { - for (int i = 0; i < 16; i++) { - reg[i] = 0; - } - cpsr = 0; -} - // Lists all thread ids that aren't deleted/etc. -std::vector g_thread_queue; +std::vector g_thread_queue; -// Lists only ready thread ids -ThreadQueueList g_thread_ready_queue; +// Lists only ready thread ids. +Common::ThreadQueueList g_thread_ready_queue; -UID g_current_thread = 0; -Thread* g_current_thread_ptr = NULL; -const char* g_hle_current_thread_name = NULL; +Handle g_current_thread_handle; -/// Creates a new thread -Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, - u32 entry_point, u32 arg, u32 stack_top, u32 processor_id, int stack_size) { +Thread* g_current_thread; - Thread *t = new Thread; - id = g_kernel_objects.Create(t); - - g_thread_queue.push_back(id); - g_thread_ready_queue.prepare(priority); - - memset(&t->nt, 0xCD, sizeof(t->nt)); - t->nt.entry_point = entry_point; - t->nt.native_size = sizeof(t->nt); - t->nt.initial_priority = t->nt.current_priority = priority; - t->nt.status = THREADSTATUS_DORMANT; - t->nt.initial_stack = t->nt.stack_top = stack_top; - t->nt.stack_size = stack_size; - t->nt.processor_id = processor_id; +inline Thread *__GetCurrentThread() { + return g_current_thread; +} - strncpy(t->nt.name, name, KERNELOBJECT_MAX_NAME_LENGTH); - t->nt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; +inline void __SetCurrentThread(Thread *t) { + g_current_thread = t; + g_current_thread_handle = t->GetHandle(); +} - t->nt.stack_size = stack_size; - t->SetupStack(stack_top, stack_size); +//////////////////////////////////////////////////////////////////////////////////////////////////// - return t; +/// Saves the current CPU context +void __KernelSaveContext(ThreadContext &ctx) { + ctx.cpu_registers[0] = Core::g_app_core->GetReg(0); + ctx.cpu_registers[1] = Core::g_app_core->GetReg(1); + ctx.cpu_registers[2] = Core::g_app_core->GetReg(2); + ctx.cpu_registers[3] = Core::g_app_core->GetReg(3); + ctx.cpu_registers[4] = Core::g_app_core->GetReg(4); + ctx.cpu_registers[5] = Core::g_app_core->GetReg(5); + ctx.cpu_registers[6] = Core::g_app_core->GetReg(6); + ctx.cpu_registers[7] = Core::g_app_core->GetReg(7); + ctx.cpu_registers[8] = Core::g_app_core->GetReg(8); + ctx.cpu_registers[9] = Core::g_app_core->GetReg(9); + ctx.cpu_registers[10] = Core::g_app_core->GetReg(10); + ctx.cpu_registers[11] = Core::g_app_core->GetReg(11); + ctx.cpu_registers[12] = Core::g_app_core->GetReg(12); + ctx.sp = Core::g_app_core->GetReg(13); + ctx.lr = Core::g_app_core->GetReg(14); + ctx.pc = Core::g_app_core->GetPC(); + ctx.cpsr = Core::g_app_core->GetCPSR(); } -UID __KernelCreateThread(UID module_id, const char* name, u32 priority, u32 entry_point, u32 arg, - u32 stack_top, u32 processor_id, int stack_size) { - UID id; - __KernelCreateThread(id, module_id, name, priority, entry_point, arg, stack_top, processor_id, - stack_size); - - HLE::EatCycles(32000); - HLE::ReSchedule("thread created"); - - return id; +/// Loads a CPU context +void __KernelLoadContext(const ThreadContext &ctx) { + Core::g_app_core->SetReg(0, ctx.cpu_registers[0]); + Core::g_app_core->SetReg(1, ctx.cpu_registers[1]); + Core::g_app_core->SetReg(2, ctx.cpu_registers[2]); + Core::g_app_core->SetReg(3, ctx.cpu_registers[3]); + Core::g_app_core->SetReg(4, ctx.cpu_registers[4]); + Core::g_app_core->SetReg(5, ctx.cpu_registers[5]); + Core::g_app_core->SetReg(6, ctx.cpu_registers[6]); + Core::g_app_core->SetReg(7, ctx.cpu_registers[7]); + Core::g_app_core->SetReg(8, ctx.cpu_registers[8]); + Core::g_app_core->SetReg(9, ctx.cpu_registers[9]); + Core::g_app_core->SetReg(10, ctx.cpu_registers[10]); + Core::g_app_core->SetReg(11, ctx.cpu_registers[11]); + Core::g_app_core->SetReg(12, ctx.cpu_registers[12]); + Core::g_app_core->SetReg(13, ctx.sp); + Core::g_app_core->SetReg(14, ctx.lr); + //Core::g_app_core->SetReg(15, ctx.pc); + + Core::g_app_core->SetPC(ctx.pc); + Core::g_app_core->SetCPSR(ctx.cpsr); } -/// Resets the specified thread back to initial calling state -void __KernelResetThread(Thread *t, int lowest_priority) { - t->context.reset(); - t->context.pc = t->nt.entry_point; - t->context.reg[13] = t->nt.initial_stack; +/// Resets a thread +void __KernelResetThread(Thread *t, s32 lowest_priority) { + memset(&t->context, 0, sizeof(ThreadContext)); - // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd... - if (t->nt.current_priority < lowest_priority) { - t->nt.current_priority = t->nt.initial_priority; + t->context.pc = t->entry_point; + t->context.sp = t->stack_top; + + if (t->current_priority < lowest_priority) { + t->current_priority = t->initial_priority; } - - memset(&t->waitInfo, 0, sizeof(t->waitInfo)); -} - -/// Returns the current executing thread -inline Thread *__GetCurrentThread() { - return g_current_thread_ptr; + + t->wait_type = WAITTYPE_NONE; } -/// Sets the current executing thread -inline void __SetCurrentThread(Thread *thread, UID thread_id, const char *name) { - g_current_thread = thread_id; - g_current_thread_ptr = thread; - g_hle_current_thread_name = name; +/// Creates a new thread +Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size=0x4000) { + static u32 _handle_count = 1; + + Thread *t = new Thread; + + handle = (_handle_count++); + + g_thread_queue.push_back(handle); + g_thread_ready_queue.prepare(priority); + + t->status = THREADSTATUS_DORMANT; + t->entry_point = entry_point; + t->stack_top = stack_top; + t->stack_size = stack_size; + t->initial_priority = t->current_priority = priority; + t->processor_id = processor_id; + t->wait_type = WAITTYPE_NONE; + + strncpy(t->name, name, KERNELOBJECT_MAX_NAME_LENGTH); + t->name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; + + return t; } -// TODO: Use __KernelChangeThreadState instead? It has other affects... -void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready) { - // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc. - _dbg_assert_msg_(KERNEL, thread->GetUID() == thread_id, "Incorrect thread_id"); - int prio = thread->nt.current_priority; - - if (thread->IsReady()) { - if (!ready) - g_thread_ready_queue.remove(prio, thread_id); - } else if (ready) { - if (thread->IsRunning()) { - g_thread_ready_queue.push_front(prio, thread_id); +/// Change a thread to "ready" state +void __KernelChangeReadyState(Thread *t, bool ready) { + Handle handle = t->GetHandle(); + if (t->IsReady()) { + if (!ready) { + g_thread_ready_queue.remove(t->current_priority, handle); + } + } else if (ready) { + if (t->IsRunning()) { + g_thread_ready_queue.push_front(t->current_priority, handle); } else { - g_thread_ready_queue.push_back(prio, thread_id); + g_thread_ready_queue.push_back(t->current_priority, handle); } - thread->nt.status = THREADSTATUS_READY; + t->status = THREADSTATUS_READY; } } -void __KernelChangeReadyState(UID thread_id, bool ready) { - u32 error; - Thread *thread = g_kernel_objects.Get(thread_id, error); - if (thread) { - __KernelChangeReadyState(thread, thread_id, ready); - } else { - WARN_LOG(KERNEL, "Trying to change the ready state of an unknown thread?"); +/// Changes a threads state +void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) { + if (!t || t->status == new_status) { + return; + } + __KernelChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); + t->status = new_status; + + if (new_status == THREADSTATUS_WAIT) { + if (t->wait_type == WAITTYPE_NONE) { + printf("ERROR: Waittype none not allowed here\n"); + } } } -/// Returns NULL if the current thread is fine. -Thread* __KernelNextThread() { - UID best_thread; - - // If the current thread is running, it's a valid candidate. +/// Switches CPU context to that of the specified thread +void __KernelSwitchContext(Thread* t, const char *reason) { Thread *cur = __GetCurrentThread(); - if (cur && cur->IsRunning()) { - best_thread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority); - if (best_thread != 0) { - __KernelChangeReadyState(cur, g_current_thread, true); + + // Save context for current thread + if (cur) { + __KernelSaveContext(cur->context); + + if (cur->IsRunning()) { + __KernelChangeReadyState(cur, true); } - } else { - best_thread = g_thread_ready_queue.pop_first(); } - // Assume g_thread_ready_queue has not become corrupt. - if (best_thread != 0) { - return g_kernel_objects.GetFast(best_thread); + // Load context of new thread + if (t) { + __SetCurrentThread(t); + __KernelChangeReadyState(t, false); + t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; + t->wait_type = WAITTYPE_NONE; + __KernelLoadContext(t->context); } else { - return NULL; + __SetCurrentThread(NULL); } } -/// Saves the current CPU context -void __KernelSaveContext(ThreadContext *ctx) { - ctx->reg[0] = Core::g_app_core->GetReg(0); - ctx->reg[1] = Core::g_app_core->GetReg(1); - ctx->reg[2] = Core::g_app_core->GetReg(2); - ctx->reg[3] = Core::g_app_core->GetReg(3); - ctx->reg[4] = Core::g_app_core->GetReg(4); - ctx->reg[5] = Core::g_app_core->GetReg(5); - ctx->reg[6] = Core::g_app_core->GetReg(6); - ctx->reg[7] = Core::g_app_core->GetReg(7); - ctx->reg[8] = Core::g_app_core->GetReg(8); - ctx->reg[9] = Core::g_app_core->GetReg(9); - ctx->reg[10] = Core::g_app_core->GetReg(10); - ctx->reg[11] = Core::g_app_core->GetReg(11); - ctx->reg[12] = Core::g_app_core->GetReg(12); - ctx->reg[13] = Core::g_app_core->GetReg(13); - ctx->reg[14] = Core::g_app_core->GetReg(14); - ctx->reg[15] = Core::g_app_core->GetReg(15); - ctx->pc = Core::g_app_core->GetPC(); - ctx->cpsr = Core::g_app_core->GetCPSR(); -} - -/// Loads a CPU context -void __KernelLoadContext(ThreadContext *ctx) { - Core::g_app_core->SetReg(0, ctx->reg[0]); - Core::g_app_core->SetReg(1, ctx->reg[1]); - Core::g_app_core->SetReg(2, ctx->reg[2]); - Core::g_app_core->SetReg(3, ctx->reg[3]); - Core::g_app_core->SetReg(4, ctx->reg[4]); - Core::g_app_core->SetReg(5, ctx->reg[5]); - Core::g_app_core->SetReg(6, ctx->reg[6]); - Core::g_app_core->SetReg(7, ctx->reg[7]); - Core::g_app_core->SetReg(8, ctx->reg[8]); - Core::g_app_core->SetReg(9, ctx->reg[9]); - Core::g_app_core->SetReg(10, ctx->reg[10]); - Core::g_app_core->SetReg(11, ctx->reg[11]); - Core::g_app_core->SetReg(12, ctx->reg[12]); - Core::g_app_core->SetReg(13, ctx->reg[13]); - Core::g_app_core->SetReg(14, ctx->reg[14]); - Core::g_app_core->SetReg(15, ctx->reg[15]); - Core::g_app_core->SetPC(ctx->pc); - Core::g_app_core->SetCPSR(ctx->cpsr); -} - -/// Switches thread context -void __KernelSwitchContext(Thread *target, const char *reason) { - u32 old_pc = 0; - UID old_uid = 0; - const char *old_name = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)"; +/// Gets the next thread that is ready to be run by priority +Thread *__KernelNextThread() { + Handle next; Thread *cur = __GetCurrentThread(); - - if (cur) { // It might just have been deleted. - __KernelSaveContext(&cur->context); - old_pc = Core::g_app_core->GetPC(); - old_uid = cur->GetUID(); - - // Normally this is taken care of in __KernelNextThread(). - if (cur->IsRunning()) - __KernelChangeReadyState(cur, old_uid, true); + + if (cur && cur->IsRunning()) { + next = g_thread_ready_queue.pop_first_better(cur->current_priority); + } else { + next = g_thread_ready_queue.pop_first(); } - if (target) { - __SetCurrentThread(target, target->GetUID(), target->nt.name); - __KernelChangeReadyState(target, g_current_thread, false); - - target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; - - __KernelLoadContext(&target->context); - } else { - __SetCurrentThread(NULL, 0, NULL); + if (next < 0) { + return NULL; } + return g_kernel_objects.GetFast(next); } -bool __KernelSwitchToThread(UID thread_id, const char *reason) { - if (!reason) { - reason = "switch to thread"; +/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) +void __KernelCallThread(Thread *t) { + // Stop waiting + if (t->wait_type != WAITTYPE_NONE) { + t->wait_type = WAITTYPE_NONE; } - if (g_current_thread == thread_id) { - return false; - } - u32 error; - Thread *t = g_kernel_objects.Get(thread_id, error); - if (!t) { - ERROR_LOG(KERNEL, "__KernelSwitchToThread: %x doesn't exist", thread_id); - HLE::ReSchedule("switch to deleted thread"); - } else if (t->IsReady() || t->IsRunning()) { - Thread *current = __GetCurrentThread(); - if (current && current->IsRunning()) { - __KernelChangeReadyState(current, g_current_thread, true); - } - __KernelSwitchContext(t, reason); - return true; - } else { - HLE::ReSchedule("switch to waiting thread"); - } - return false; + __KernelChangeThreadState(t, THREADSTATUS_READY); } -/// Sets up the root (primary) thread of execution -UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) { - UID id; - - Thread *thread = __KernelCreateThread(id, module_id, "root", prio, Core::g_app_core->GetPC(), - arg, Memory::SCRATCHPAD_VADDR_END, 0xFFFFFFFE, stack_size=stack_size); - - if (thread->current_stack.start == 0) { - ERROR_LOG(KERNEL, "Unable to allocate stack for root thread."); - } - __KernelResetThread(thread, 0); - - Thread *prev_thread = __GetCurrentThread(); - if (prev_thread && prev_thread->IsRunning()) - __KernelChangeReadyState(g_current_thread, true); - __SetCurrentThread(thread, id, "root"); - thread->nt.status = THREADSTATUS_RUNNING; // do not schedule - - strcpy(thread->nt.name, "root"); - - __KernelLoadContext(&thread->context); +/// Sets up the primary application thread +Handle __KernelSetupMainThread(s32 priority, int stack_size) { + Handle handle; - // NOTE(bunnei): Not sure this is really correct, ignore args for now... - //Core::g_app_core->SetReg(0, args); - //Core::g_app_core->SetReg(13, (args + 0xf) & ~0xf); // Setup SP - probably not correct - //u32 location = Core::g_app_core->GetReg(13); // SP - //Core::g_app_core->SetReg(1, location); + // Initialize new "main" thread + Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, + 0xFFFFFFFE, Memory::SCRATCHPAD_VADDR_END, stack_size); - //if (argp) - // Memory::Memcpy(location, argp, args); - //// Let's assume same as starting a new thread, 64 bytes for safety/kernel. - //Core::g_app_core->SetReg(13, Core::g_app_core->GetReg(13) - 64); - - return id; -} - -int __KernelRotateThreadReadyQueue(int priority) { + __KernelResetThread(t, 0); + + // If running another thread already, set it to "ready" state Thread *cur = __GetCurrentThread(); - - // 0 is special, it means "my current priority." - if (priority == 0) { - priority = cur->nt.current_priority; + if (cur && cur->IsRunning()) { + __KernelChangeReadyState(cur, true); } - //if (priority <= 0x07 || priority > 0x77) - // return SCE_KERNEL_ERROR_ILLEGAL_PRIORITY; + + // Run new "main" thread + __SetCurrentThread(t); + t->status = THREADSTATUS_RUNNING; + __KernelLoadContext(t->context); - if (!g_thread_ready_queue.empty(priority)) { - // In other words, yield to everyone else. - if (cur->nt.current_priority == priority) { - g_thread_ready_queue.push_back(priority, g_current_thread); - cur->nt.status = (cur->nt.status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; + return handle; +} - // Yield the next thread of this priority to all other threads of same priority. - } else { - g_thread_ready_queue.rotate(priority); +/// Resumes a thread from waiting by marking it as "ready" +void __KernelResumeThreadFromWait(Handle handle) { + u32 error; + Thread *t = g_kernel_objects.Get(handle, error); + if (t) { + t->status &= ~THREADSTATUS_WAIT; + if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { + __KernelChangeReadyState(t, true); } } - HLE::EatCycles(250); - HLE::ReSchedule("rotatethreadreadyqueue"); +} - return 0; +/// Puts a thread in the wait state for the given type/reason +void __KernelWaitCurThread(WaitType wait_type, const char *reason) { + Thread *t = __GetCurrentThread(); + t->wait_type = wait_type; + __KernelChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); } +/// Reschedules to the next available thread (call after current thread is suspended) +void __KernelReschedule(const char *reason) { + Thread *next = __KernelNextThread(); + if (next > 0) { + __KernelSwitchContext(next, reason); + } +} + + void __KernelThreadingInit() { } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 05468fb2e0..cca4e85fd5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -7,50 +7,10 @@ #include "common/common_types.h" #include "core/hle/kernel/kernel.h" -enum ThreadStatus { - THREADSTATUS_RUNNING = 1, - THREADSTATUS_READY = 2, - THREADSTATUS_WAIT = 4, - THREADSTATUS_SUSPEND = 8, - THREADSTATUS_DORMANT = 16, - THREADSTATUS_DEAD = 32, - - THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND -}; - -struct ThreadContext { - void reset(); - - u32 reg[16]; - u32 cpsr; - u32 pc; -}; - class Thread; -Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, u32 entrypoint, - u32 arg, u32 stack_top, u32 processor_id, int stack_size=0x4000); - -UID __KernelCreateThread(UID module_id, const char* name, u32 priority, u32 entry_point, u32 arg, - u32 stack_top, u32 processor_id, int stack_size=0x4000); - -void __KernelResetThread(Thread *t, int lowest_priority); -void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready); -void __KernelChangeReadyState(UID thread_id, bool ready); -Thread* __KernelNextThread(); -void __KernelSaveContext(ThreadContext *ctx); -void __KernelLoadContext(ThreadContext *ctx); -void __KernelSwitchContext(Thread *target, const char *reason); -bool __KernelSwitchToThread(UID thread_id, const char *reason); -UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size=0x4000); -int __KernelRotateThreadReadyQueue(int priority=0); +/// Sets up the primary application thread +Handle __KernelSetupMainThread(s32 priority, int stack_size=0x4000); void __KernelThreadingInit(); void __KernelThreadingShutdown(); - -//const char *__KernelGetThreadName(SceUID threadID); -// -//void __KernelSaveContext(ThreadContext *ctx); -//void __KernelLoadContext(ThreadContext *ctx); - -//void __KernelSwitchContext(Thread *target, const char *reason); \ No newline at end of file -- cgit v1.2.3 From 7cdb70505944b2ed456d7f5376594e05f3b3357f Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 16 May 2014 23:48:15 -0400 Subject: - replaced KERNELOBJECT_MAX_NAME_LENGTH with KERNEL_MAX_NAME_LENGTH - added KERNEL_DEFAULT_STACK_SIZE definition (0x4000) --- src/core/hle/kernel/kernel.h | 5 ++--- src/core/hle/kernel/thread.cpp | 9 +++++---- src/core/hle/kernel/thread.h | 6 +++++- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 24d422682e..2608eecc91 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -16,11 +16,10 @@ enum KernelIDType { }; enum { - KERNELOBJECT_MAX_NAME_LENGTH = 255, + KERNEL_MAX_NAME_LENGTH = 0x100, + KERNEL_DEFAULT_STACK_SIZE = 0x4000, }; -#define KERNELOBJECT_MAX_NAME_LENGTH 31 - class KernelObjectPool; class KernelObject { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 833a1b4bad..76a73747d8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -81,7 +81,7 @@ public: WaitType wait_type; - char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; + char name[KERNEL_MAX_NAME_LENGTH+1]; }; // Lists all thread ids that aren't deleted/etc. @@ -165,7 +165,8 @@ void __KernelResetThread(Thread *t, s32 lowest_priority) { } /// Creates a new thread -Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size=0x4000) { +Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, + s32 processor_id, u32 stack_top, int stack_size) { static u32 _handle_count = 1; Thread *t = new Thread; @@ -183,8 +184,8 @@ Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, t->processor_id = processor_id; t->wait_type = WAITTYPE_NONE; - strncpy(t->name, name, KERNELOBJECT_MAX_NAME_LENGTH); - t->name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; + strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH); + t->name[KERNEL_MAX_NAME_LENGTH] = '\0'; return t; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index cca4e85fd5..add6107d76 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -9,8 +9,12 @@ class Thread; +/// Creates a new thread +Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, + s32 processor_id, u32 stack_top, int stack_size=KERNEL_DEFAULT_STACK_SIZE); + /// Sets up the primary application thread -Handle __KernelSetupMainThread(s32 priority, int stack_size=0x4000); +Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK_SIZE); void __KernelThreadingInit(); void __KernelThreadingShutdown(); -- cgit v1.2.3 From 14ae026386cf3f984d60401e2104165c3ca3266b Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 May 2014 00:56:00 -0400 Subject: - added enum ThreadProcessorId - reorganized some kernel thread functions - added placeholder __KernelWaitThread_Synchronization function --- src/core/hle/kernel/thread.cpp | 141 ++++++++++++++++++++++++++--------------- src/core/hle/kernel/thread.h | 19 +++++- 2 files changed, 107 insertions(+), 53 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 76a73747d8..b967b3c624 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -21,20 +21,14 @@ // Enums -enum ThreadPriority { - THREADPRIO_HIGHEST = 0, - THREADPRIO_DEFAULT = 16, - THREADPRIO_LOWEST = 31, -}; - enum ThreadStatus { - THREADSTATUS_RUNNING = 1, - THREADSTATUS_READY = 2, - THREADSTATUS_WAIT = 4, - THREADSTATUS_SUSPEND = 8, - THREADSTATUS_DORMANT = 16, - THREADSTATUS_DEAD = 32, - THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND + THREADSTATUS_RUNNING = 1, + THREADSTATUS_READY = 2, + THREADSTATUS_WAIT = 4, + THREADSTATUS_SUSPEND = 8, + THREADSTATUS_DORMANT = 16, + THREADSTATUS_DEAD = 32, + THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND }; enum WaitType { @@ -46,8 +40,6 @@ enum WaitType { WAITTYPE_VBLANK, WAITTYPE_MUTEX, WAITTYPE_SYNCH, - - NUM_WAITTYPES }; typedef s32 Handle; @@ -164,32 +156,6 @@ void __KernelResetThread(Thread *t, s32 lowest_priority) { t->wait_type = WAITTYPE_NONE; } -/// Creates a new thread -Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, - s32 processor_id, u32 stack_top, int stack_size) { - static u32 _handle_count = 1; - - Thread *t = new Thread; - - handle = (_handle_count++); - - g_thread_queue.push_back(handle); - g_thread_ready_queue.prepare(priority); - - t->status = THREADSTATUS_DORMANT; - t->entry_point = entry_point; - t->stack_top = stack_top; - t->stack_size = stack_size; - t->initial_priority = t->current_priority = priority; - t->processor_id = processor_id; - t->wait_type = WAITTYPE_NONE; - - strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH); - t->name[KERNEL_MAX_NAME_LENGTH] = '\0'; - - return t; -} - /// Change a thread to "ready" state void __KernelChangeReadyState(Thread *t, bool ready) { Handle handle = t->GetHandle(); @@ -222,6 +188,79 @@ void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) { } } +/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) +void __KernelCallThread(Thread *t) { + // Stop waiting + if (t->wait_type != WAITTYPE_NONE) { + t->wait_type = WAITTYPE_NONE; + } + __KernelChangeThreadState(t, THREADSTATUS_READY); +} + +/// Creates a new thread +Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, + s32 processor_id, u32 stack_top, int stack_size) { + + Thread *t = new Thread; + + handle = g_kernel_objects.Create(t); + + g_thread_queue.push_back(handle); + g_thread_ready_queue.prepare(priority); + + t->status = THREADSTATUS_DORMANT; + t->entry_point = entry_point; + t->stack_top = stack_top; + t->stack_size = stack_size; + t->initial_priority = t->current_priority = priority; + t->processor_id = processor_id; + t->wait_type = WAITTYPE_NONE; + + strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH); + t->name[KERNEL_MAX_NAME_LENGTH] = '\0'; + + return t; +} + +/// Creates a new thread - wrapper for external user +Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 processor_id, + u32 stack_top, int stack_size) { + if (name == NULL) { + ERROR_LOG(KERNEL, "__KernelCreateThread(): NULL name"); + return -1; + } + if ((u32)stack_size < 0x200) { + ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid stack_size=0x%08X", name, + stack_size); + return -1; + } + if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { + s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); + WARN_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid priority=0x%08X, clamping to %08X", + name, priority, new_priority); + // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm + // validity of this + priority = new_priority; + } + if (!Memory::GetPointer(entry_point)) { + ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid entry %08x", name, entry_point); + return -1; + } + Handle handle; + Thread *t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top, + stack_size); + + HLE::EatCycles(32000); + + // This won't schedule to the new thread, but it may to one woken from eating cycles. + // Technically, this should not eat all at once, and reschedule in the middle, but that's hard. + HLE::ReSchedule("thread created"); + + __KernelCallThread(t); + + return handle; +} + /// Switches CPU context to that of the specified thread void __KernelSwitchContext(Thread* t, const char *reason) { Thread *cur = __GetCurrentThread(); @@ -262,22 +301,13 @@ Thread *__KernelNextThread() { return g_kernel_objects.GetFast(next); } -/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) -void __KernelCallThread(Thread *t) { - // Stop waiting - if (t->wait_type != WAITTYPE_NONE) { - t->wait_type = WAITTYPE_NONE; - } - __KernelChangeThreadState(t, THREADSTATUS_READY); -} - /// Sets up the primary application thread Handle __KernelSetupMainThread(s32 priority, int stack_size) { Handle handle; // Initialize new "main" thread Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, - 0xFFFFFFFE, Memory::SCRATCHPAD_VADDR_END, stack_size); + THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); __KernelResetThread(t, 0); @@ -322,6 +352,15 @@ void __KernelReschedule(const char *reason) { } } +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Wait thread - on WaitSynchronization +void __KernelWaitThread_Synchronization() { + // TODO(bunnei): Just a placeholder function for now... FixMe + __KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// void __KernelThreadingInit() { } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index add6107d76..8138be26f7 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -9,8 +9,20 @@ class Thread; -/// Creates a new thread -Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, +enum ThreadPriority { + THREADPRIO_HIGHEST = 0, + THREADPRIO_DEFAULT = 16, + THREADPRIO_LOWEST = 31, +}; + +enum ThreadProcessorId { + THREADPROCESSORID_0 = 0xFFFFFFFE, + THREADPROCESSORID_1 = 0xFFFFFFFD, + THREADPROCESSORID_ALL = 0xFFFFFFFC, +}; + +/// Creates a new thread - wrapper for external user +Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size=KERNEL_DEFAULT_STACK_SIZE); /// Sets up the primary application thread @@ -18,3 +30,6 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK void __KernelThreadingInit(); void __KernelThreadingShutdown(); + +/// Wait thread - on WaitSynchronization +void __KernelWaitThread_Synchronization(); -- cgit v1.2.3 From 09b8e8fb6afbbcc3dd6127ee02f7ac1611eb85aa Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 May 2014 13:47:55 -0400 Subject: changed a comment --- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/thread.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b967b3c624..d0bc9c8d84 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -354,7 +354,7 @@ void __KernelReschedule(const char *reason) { //////////////////////////////////////////////////////////////////////////////////////////////////// -/// Wait thread - on WaitSynchronization +/// Put current thread in a wait state - on WaitSynchronization void __KernelWaitThread_Synchronization() { // TODO(bunnei): Just a placeholder function for now... FixMe __KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called"); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 8138be26f7..0d0f465000 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -31,5 +31,5 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK void __KernelThreadingInit(); void __KernelThreadingShutdown(); -/// Wait thread - on WaitSynchronization +/// Put current thread in a wait state - on WaitSynchronization void __KernelWaitThread_Synchronization(); -- cgit v1.2.3 From 772abad77803809d8ee857efc0d7e29c36c6b2cb Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 May 2014 18:12:29 -0400 Subject: - moved Handle/Result definitions to kernel.h - added ResetType enum --- src/core/hle/kernel/kernel.h | 3 ++- src/core/hle/kernel/thread.cpp | 2 -- src/core/hle/service/service.h | 12 +++++++----- src/core/hle/service/srv.cpp | 2 +- src/core/hle/service/srv.h | 2 +- src/core/hle/syscall.h | 12 ++++++++---- 6 files changed, 19 insertions(+), 14 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2608eecc91..d4bb28c728 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -6,7 +6,8 @@ #include "common/common_types.h" -typedef s32 Handle; +typedef u32 Handle; +typedef s32 Result; enum KernelIDType { KERNEL_ID_TYPE_THREAD = 1, diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d0bc9c8d84..634218e8ba 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -42,8 +42,6 @@ enum WaitType { WAITTYPE_SYNCH, }; -typedef s32 Handle; - class Thread : public KernelObject { public: diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index b260a290a0..026e3d5de1 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -11,6 +11,8 @@ #include "common/common.h" #include "common/common_types.h" #include "core/mem_map.h" + +#include "core/hle/kernel/kernel.h" #include "core/hle/syscall.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -70,14 +72,14 @@ public: } /// Allocates a new handle for the service - Syscall::Handle NewHandle() { - Syscall::Handle handle = (m_handles.size() << 16) | m_uid; + Handle NewHandle() { + Handle handle = (m_handles.size() << 16) | m_uid; m_handles.push_back(handle); return handle; } /// Frees a handle from the service - void DeleteHandle(Syscall::Handle handle) { + void DeleteHandle(Handle handle) { for(auto iter = m_handles.begin(); iter != m_handles.end(); ++iter) { if(*iter == handle) { m_handles.erase(iter); @@ -90,7 +92,7 @@ public: * Called when svcSendSyncRequest is called, loads command buffer and executes comand * @return Return result of svcSendSyncRequest passed back to user app */ - Syscall::Result Sync() { + Result Sync() { u32* cmd_buff = GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -124,7 +126,7 @@ protected: private: u32 m_uid; - std::vector m_handles; + std::vector m_handles; std::map m_functions; }; diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 303a943d4f..a3d0411767 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -23,7 +23,7 @@ void GetProcSemaphore(Service::Interface* self) { } void GetServiceHandle(Service::Interface* self) { - Syscall::Result res = 0; + Result res = 0; u32* cmd_buff = Service::GetCommandBuffer(); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 760c976b48..f465ebc06f 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h @@ -30,7 +30,7 @@ public: * Called when svcSendSyncRequest is called, loads command buffer and executes comand * @return Return result of svcSendSyncRequest passed back to user app */ - Syscall::Result Sync(); + Result Sync(); }; diff --git a/src/core/hle/syscall.h b/src/core/hle/syscall.h index 17f1902661..3da349ed5f 100644 --- a/src/core/hle/syscall.h +++ b/src/core/hle/syscall.h @@ -7,7 +7,7 @@ #include "common/common_types.h" //////////////////////////////////////////////////////////////////////////////////////////////////// -// SVC structures +// SVC types struct MemoryInfo { u32 base_address; @@ -31,14 +31,18 @@ struct ThreadContext { u32 fpexc; }; +enum ResetType { + RESETTYPE_ONESHOT, + RESETTYPE_STICKY, + RESETTYPE_PULSE, + RESETTYPE_MAX_BIT = (1u << 31), +}; + //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Syscall namespace Syscall { -typedef u32 Handle; -typedef s32 Result; - void Register(); } // namespace -- cgit v1.2.3 From 44336329eddd7dbe1f76144e9a1e95e5f76ed372 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 18:13:25 -0400 Subject: - created a Kernel namespace - cleaned up Kernel code a bit (moved stuff into namespace, fixed whitespace issues) - added handle types for all different CTROS handles --- src/core/hle/kernel/kernel.cpp | 49 +++++++++++++------------- src/core/hle/kernel/kernel.h | 75 +++++++++++++++++++++++----------------- src/core/hle/kernel/thread.cpp | 18 +++++----- src/core/hle/kernel/thread.h | 4 +-- src/core/hle/service/service.cpp | 4 +-- src/core/hle/service/service.h | 12 +++---- 6 files changed, 87 insertions(+), 75 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f7145ddd8f..b1fdffde5e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -12,22 +12,16 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -KernelObjectPool g_kernel_objects; +namespace Kernel { -void __KernelInit() { - __KernelThreadingInit(); -} - -void __KernelShutdown() { - __KernelThreadingShutdown(); -} +ObjectPool g_object_pool; -KernelObjectPool::KernelObjectPool() { +ObjectPool::ObjectPool() { memset(occupied, 0, sizeof(bool) * MAX_COUNT); next_id = INITIAL_NEXT_ID; } -Handle KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) { +Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) { if (range_top > MAX_COUNT) { range_top = MAX_COUNT; } @@ -46,8 +40,7 @@ Handle KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_t return 0; } -bool KernelObjectPool::IsValid(Handle handle) -{ +bool ObjectPool::IsValid(Handle handle) { int index = handle - HANDLE_OFFSET; if (index < 0) return false; @@ -57,26 +50,24 @@ bool KernelObjectPool::IsValid(Handle handle) return occupied[index]; } -void KernelObjectPool::Clear() -{ - for (int i = 0; i < MAX_COUNT; i++) - { +void ObjectPool::Clear() { + for (int i = 0; i < MAX_COUNT; i++) { //brutally clear everything, no validation if (occupied[i]) delete pool[i]; occupied[i] = false; } - memset(pool, 0, sizeof(KernelObject*)*MAX_COUNT); + memset(pool, 0, sizeof(Object*)*MAX_COUNT); next_id = INITIAL_NEXT_ID; } -KernelObject *&KernelObjectPool::operator [](Handle handle) +Object* &ObjectPool::operator [](Handle handle) { _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); return pool[handle - HANDLE_OFFSET]; } -void KernelObjectPool::List() { +void ObjectPool::List() { for (int i = 0; i < MAX_COUNT; i++) { if (occupied[i]) { if (pool[i]) { @@ -87,18 +78,16 @@ void KernelObjectPool::List() { } } -int KernelObjectPool::GetCount() -{ +int ObjectPool::GetCount() { int count = 0; - for (int i = 0; i < MAX_COUNT; i++) - { + for (int i = 0; i < MAX_COUNT; i++) { if (occupied[i]) count++; } return count; } -KernelObject *KernelObjectPool::CreateByIDType(int type) { +Object* ObjectPool::CreateByIDType(int type) { // Used for save states. This is ugly, but what other way is there? switch (type) { //case SCE_KERNEL_TMID_Alarm: @@ -142,8 +131,18 @@ KernelObject *KernelObjectPool::CreateByIDType(int type) { } } +void Init() { + __KernelThreadingInit(); +} + +void Shutdown() { + __KernelThreadingShutdown(); +} + +} // namespace + bool __KernelLoadExec(u32 entry_point) { - __KernelInit(); + Kernel::Init(); Core::g_app_core->SetPC(entry_point); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 8f2b7b36da..19edb7b57f 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -9,41 +9,50 @@ typedef u32 Handle; typedef s32 Result; -enum KernelIDType { - KERNEL_ID_TYPE_THREAD, - KERNEL_ID_TYPE_SEMAPHORE, - KERNEL_ID_TYPE_MUTEX, - KERNEL_ID_TYPE_EVENT, - KERNEL_ID_TYPE_SERVICE, +namespace Kernel { + +enum class HandleType : u32 { + Unknown = 0, + Port = 1, + Service = 2, + Event = 3, + Mutex = 4, + SharedMemory = 5, + Redirection = 6, + Thread = 7, + Process = 8, + Arbiter = 9, + File = 10, + Semaphore = 11, }; - + enum { - KERNEL_MAX_NAME_LENGTH = 0x100, - KERNEL_DEFAULT_STACK_SIZE = 0x4000, + MAX_NAME_LENGTH = 0x100, + DEFAULT_STACK_SIZE = 0x4000, }; -class KernelObjectPool; +class ObjectPool; -class KernelObject { - friend class KernelObjectPool; +class Object : NonCopyable { + friend class ObjectPool; u32 handle; public: - virtual ~KernelObject() {} + virtual ~Object() {} Handle GetHandle() const { return handle; } virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } - virtual KernelIDType GetIDType() const = 0; + virtual Kernel::HandleType GetHandleType() const = 0; }; -class KernelObjectPool { +class ObjectPool : NonCopyable { public: - KernelObjectPool(); - ~KernelObjectPool() {} + ObjectPool(); + ~ObjectPool() {} // Allocates a handle within the range and inserts the object into the map. - Handle Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); + Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); - static KernelObject *CreateByIDType(int type); + static Object* CreateByIDType(int type); template u32 Destroy(Handle handle) { @@ -71,7 +80,7 @@ public: // it just acted as a static case and everything worked. This means that we will never // see the Wrong type object error below, but we'll just have to live with that danger. T* t = static_cast(pool[handle - HANDLE_OFFSET]); - if (t == 0 || t->GetIDType() != T::GetStaticIDType()) { + if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) { WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); outError = 0;//T::GetMissingErrorCode(); return 0; @@ -86,17 +95,17 @@ public: T *GetFast(Handle handle) { const Handle realHandle = handle - HANDLE_OFFSET; _dbg_assert_(KERNEL, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); - return static_cast(pool[realHandle]); + return static_cast(pool[realHandle]); } template - void Iterate(bool func(T *, ArgT), ArgT arg) { + void Iterate(bool func(T*, ArgT), ArgT arg) { int type = T::GetStaticIDType(); for (int i = 0; i < MAX_COUNT; i++) { if (!occupied[i]) continue; - T *t = static_cast(pool[i]); + T* t = static_cast(pool[i]); if (t->GetIDType() == type) { if (!func(t, arg)) break; @@ -104,33 +113,37 @@ public: } } - bool GetIDType(Handle handle, int *type) const { + bool GetIDType(Handle handle, HandleType* type) const { if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || !occupied[handle - HANDLE_OFFSET]) { ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); return false; } - KernelObject *t = pool[handle - HANDLE_OFFSET]; - *type = t->GetIDType(); + Object* t = pool[handle - HANDLE_OFFSET]; + *type = t->GetHandleType(); return true; } - KernelObject *&operator [](Handle handle); + Object* &operator [](Handle handle); void List(); void Clear(); int GetCount(); private: + enum { MAX_COUNT = 0x1000, HANDLE_OFFSET = 0x100, INITIAL_NEXT_ID = 0x10, }; - KernelObject *pool[MAX_COUNT]; - bool occupied[MAX_COUNT]; - int next_id; + + Object* pool[MAX_COUNT]; + bool occupied[MAX_COUNT]; + int next_id; }; -extern KernelObjectPool g_kernel_objects; +extern ObjectPool g_object_pool; + +} // namespace bool __KernelLoadExec(u32 entry_point); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 634218e8ba..2955d6f5b2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -42,14 +42,14 @@ enum WaitType { WAITTYPE_SYNCH, }; -class Thread : public KernelObject { +class Thread : public Kernel::Object { public: const char *GetName() { return name; } const char *GetTypeName() { return "Thread"; } - static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; } - KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; } + static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } + Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } @@ -71,7 +71,7 @@ public: WaitType wait_type; - char name[KERNEL_MAX_NAME_LENGTH+1]; + char name[Kernel::MAX_NAME_LENGTH + 1]; }; // Lists all thread ids that aren't deleted/etc. @@ -201,7 +201,7 @@ Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, Thread *t = new Thread; - handle = g_kernel_objects.Create(t); + handle = Kernel::g_object_pool.Create(t); g_thread_queue.push_back(handle); g_thread_ready_queue.prepare(priority); @@ -214,8 +214,8 @@ Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, t->processor_id = processor_id; t->wait_type = WAITTYPE_NONE; - strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH); - t->name[KERNEL_MAX_NAME_LENGTH] = '\0'; + strncpy(t->name, name, Kernel::MAX_NAME_LENGTH); + t->name[Kernel::MAX_NAME_LENGTH] = '\0'; return t; } @@ -296,7 +296,7 @@ Thread *__KernelNextThread() { if (next < 0) { return NULL; } - return g_kernel_objects.GetFast(next); + return Kernel::g_object_pool.GetFast(next); } /// Sets up the primary application thread @@ -326,7 +326,7 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size) { /// Resumes a thread from waiting by marking it as "ready" void __KernelResumeThreadFromWait(Handle handle) { u32 error; - Thread *t = g_kernel_objects.Get(handle, error); + Thread *t = Kernel::g_object_pool.Get(handle, error); if (t) { t->status &= ~THREADSTATUS_WAIT; if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index eca84c7180..207a5227b1 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -23,10 +23,10 @@ enum ThreadProcessorId { /// Creates a new thread - wrapper for external user Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, - s32 processor_id, u32 stack_top, int stack_size=KERNEL_DEFAULT_STACK_SIZE); + s32 processor_id, u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Sets up the primary application thread -Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK_SIZE); +Handle __KernelSetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) void __KernelReschedule(const char *reason); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index b3e414e0f9..08d0c43ff5 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -34,7 +34,7 @@ Manager::~Manager() { /// Add a service to the manager (does not create it though) void Manager::AddService(Interface* service) { - m_port_map[service->GetPortName()] = g_kernel_objects.Create(service); + m_port_map[service->GetPortName()] = Kernel::g_object_pool.Create(service); m_services.push_back(service); } @@ -48,7 +48,7 @@ void Manager::DeleteService(std::string port_name) { /// Get a Service Interface from its Handle Interface* Manager::FetchFromHandle(Handle handle) { - return g_kernel_objects.GetFast(handle); + return Kernel::g_object_pool.GetFast(handle); } /// Get a Service Interface from its port diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 450a439fe0..f334dbcb8e 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -36,15 +36,15 @@ inline static u32* GetCommandBuffer(const int offset=0) { class Manager; /// Interface to a CTROS service -class Interface : public KernelObject { +class Interface : public Kernel::Object { friend class Manager; public: const char *GetName() { return GetPortName(); } const char *GetTypeName() { return GetPortName(); } - static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; } - KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; } + static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } + Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } typedef void (*Function)(Interface*); @@ -63,8 +63,8 @@ public: } /// Allocates a new handle for the service - Handle CreateHandle(KernelObject *obj) { - Handle handle = g_kernel_objects.Create(obj); + Handle CreateHandle(Kernel::Object *obj) { + Handle handle = Kernel::g_object_pool.Create(obj); m_handles.push_back(handle); return handle; } @@ -72,7 +72,7 @@ public: /// Frees a handle from the service template void DeleteHandle(const Handle handle) { - g_kernel_objects.Destroy(handle); + g_object_pool.Destroy(handle); m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); } -- cgit v1.2.3 From f654a03f1f23bea8fe5bf7194614ce6e947d0c5c Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 18:20:35 -0400 Subject: thread: whitespace change - fixed * and & placement --- src/core/hle/kernel/thread.cpp | 50 +++++++++++++++++++++--------------------- src/core/hle/kernel/thread.h | 4 ++-- 2 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 2955d6f5b2..cfc5327a3e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -45,8 +45,8 @@ enum WaitType { class Thread : public Kernel::Object { public: - const char *GetName() { return name; } - const char *GetTypeName() { return "Thread"; } + const char* GetName() { return name; } + const char* GetTypeName() { return "Thread"; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } @@ -85,11 +85,11 @@ Handle g_current_thread_handle; Thread* g_current_thread; -inline Thread *__GetCurrentThread() { +inline Thread* __GetCurrentThread() { return g_current_thread; } -inline void __SetCurrentThread(Thread *t) { +inline void __SetCurrentThread(Thread* t) { g_current_thread = t; g_current_thread_handle = t->GetHandle(); } @@ -97,7 +97,7 @@ inline void __SetCurrentThread(Thread *t) { //////////////////////////////////////////////////////////////////////////////////////////////////// /// Saves the current CPU context -void __KernelSaveContext(ThreadContext &ctx) { +void __KernelSaveContext(ThreadContext& ctx) { ctx.cpu_registers[0] = Core::g_app_core->GetReg(0); ctx.cpu_registers[1] = Core::g_app_core->GetReg(1); ctx.cpu_registers[2] = Core::g_app_core->GetReg(2); @@ -118,7 +118,7 @@ void __KernelSaveContext(ThreadContext &ctx) { } /// Loads a CPU context -void __KernelLoadContext(const ThreadContext &ctx) { +void __KernelLoadContext(const ThreadContext& ctx) { Core::g_app_core->SetReg(0, ctx.cpu_registers[0]); Core::g_app_core->SetReg(1, ctx.cpu_registers[1]); Core::g_app_core->SetReg(2, ctx.cpu_registers[2]); @@ -141,7 +141,7 @@ void __KernelLoadContext(const ThreadContext &ctx) { } /// Resets a thread -void __KernelResetThread(Thread *t, s32 lowest_priority) { +void __KernelResetThread(Thread* t, s32 lowest_priority) { memset(&t->context, 0, sizeof(ThreadContext)); t->context.pc = t->entry_point; @@ -155,7 +155,7 @@ void __KernelResetThread(Thread *t, s32 lowest_priority) { } /// Change a thread to "ready" state -void __KernelChangeReadyState(Thread *t, bool ready) { +void __KernelChangeReadyState(Thread* t, bool ready) { Handle handle = t->GetHandle(); if (t->IsReady()) { if (!ready) { @@ -172,7 +172,7 @@ void __KernelChangeReadyState(Thread *t, bool ready) { } /// Changes a threads state -void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) { +void __KernelChangeThreadState(Thread* t, ThreadStatus new_status) { if (!t || t->status == new_status) { return; } @@ -187,7 +187,7 @@ void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) { } /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) -void __KernelCallThread(Thread *t) { +void __KernelCallThread(Thread* t) { // Stop waiting if (t->wait_type != WAITTYPE_NONE) { t->wait_type = WAITTYPE_NONE; @@ -196,10 +196,10 @@ void __KernelCallThread(Thread *t) { } /// Creates a new thread -Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, +Thread* __KernelCreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { - Thread *t = new Thread; + Thread* t = new Thread; handle = Kernel::g_object_pool.Create(t); @@ -221,7 +221,7 @@ Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, } /// Creates a new thread - wrapper for external user -Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 processor_id, +Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { if (name == NULL) { ERROR_LOG(KERNEL, "__KernelCreateThread(): NULL name"); @@ -245,7 +245,7 @@ Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 return -1; } Handle handle; - Thread *t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top, + Thread* t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top, stack_size); HLE::EatCycles(32000); @@ -260,8 +260,8 @@ Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 } /// Switches CPU context to that of the specified thread -void __KernelSwitchContext(Thread* t, const char *reason) { - Thread *cur = __GetCurrentThread(); +void __KernelSwitchContext(Thread* t, const char* reason) { + Thread* cur = __GetCurrentThread(); // Save context for current thread if (cur) { @@ -284,9 +284,9 @@ void __KernelSwitchContext(Thread* t, const char *reason) { } /// Gets the next thread that is ready to be run by priority -Thread *__KernelNextThread() { +Thread* __KernelNextThread() { Handle next; - Thread *cur = __GetCurrentThread(); + Thread* cur = __GetCurrentThread(); if (cur && cur->IsRunning()) { next = g_thread_ready_queue.pop_first_better(cur->current_priority); @@ -304,13 +304,13 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size) { Handle handle; // Initialize new "main" thread - Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, + Thread* t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); __KernelResetThread(t, 0); // If running another thread already, set it to "ready" state - Thread *cur = __GetCurrentThread(); + Thread* cur = __GetCurrentThread(); if (cur && cur->IsRunning()) { __KernelChangeReadyState(cur, true); } @@ -326,7 +326,7 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size) { /// Resumes a thread from waiting by marking it as "ready" void __KernelResumeThreadFromWait(Handle handle) { u32 error; - Thread *t = Kernel::g_object_pool.Get(handle, error); + Thread* t = Kernel::g_object_pool.Get(handle, error); if (t) { t->status &= ~THREADSTATUS_WAIT; if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { @@ -336,15 +336,15 @@ void __KernelResumeThreadFromWait(Handle handle) { } /// Puts a thread in the wait state for the given type/reason -void __KernelWaitCurThread(WaitType wait_type, const char *reason) { - Thread *t = __GetCurrentThread(); +void __KernelWaitCurThread(WaitType wait_type, const char* reason) { + Thread* t = __GetCurrentThread(); t->wait_type = wait_type; __KernelChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); } /// Reschedules to the next available thread (call after current thread is suspended) -void __KernelReschedule(const char *reason) { - Thread *next = __KernelNextThread(); +void __KernelReschedule(const char* reason) { + Thread* next = __KernelNextThread(); if (next > 0) { __KernelSwitchContext(next, reason); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 207a5227b1..72e9a416de 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -22,14 +22,14 @@ enum ThreadProcessorId { }; /// Creates a new thread - wrapper for external user -Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, +Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Sets up the primary application thread Handle __KernelSetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) -void __KernelReschedule(const char *reason); +void __KernelReschedule(const char* reason); void __KernelThreadingInit(); void __KernelThreadingShutdown(); -- cgit v1.2.3 From 143bba20453036f0a4bcc74dad10d99605a84732 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 18:28:38 -0400 Subject: renamed "syscall" module to "svc" (more accurate naming) --- src/core/CMakeLists.txt | 2 +- src/core/core.vcxproj | 4 +- src/core/core.vcxproj.filters | 12 +- src/core/hle/hle.cpp | 14 +- src/core/hle/hle.h | 2 +- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/service/service.h | 2 +- src/core/hle/svc.cpp | 350 +++++++++++++++++++++++++++++++++++++++++ src/core/hle/svc.h | 48 ++++++ src/core/hle/syscall.cpp | 348 ---------------------------------------- src/core/hle/syscall.h | 48 ------ 11 files changed, 417 insertions(+), 415 deletions(-) create mode 100644 src/core/hle/svc.cpp create mode 100644 src/core/hle/svc.h delete mode 100644 src/core/hle/syscall.cpp delete mode 100644 src/core/hle/syscall.h (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b0597db385..e006502da5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -33,7 +33,7 @@ set(SRCS core.cpp hle/hle.cpp hle/config_mem.cpp hle/coprocessor.cpp - hle/syscall.cpp + hle/svc.cpp hle/kernel/kernel.cpp hle/kernel/thread.cpp hle/service/apt.cpp diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index f077154ee1..6eb58a636c 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -175,7 +175,7 @@ - + @@ -223,7 +223,7 @@ - + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 6aedeb54b0..fc4e35edb0 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -84,9 +84,6 @@ hle - - hle - hle\service @@ -162,6 +159,9 @@ hle\kernel + + hle + @@ -226,9 +226,6 @@ hle\service - - hle - hle\service @@ -289,6 +286,9 @@ hle\kernel + + hle + diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 4523845711..080c36abf4 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -6,7 +6,7 @@ #include "core/mem_map.h" #include "core/hle/hle.h" -#include "core/hle/syscall.h" +#include "core/hle/svc.h" #include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -15,17 +15,17 @@ namespace HLE { static std::vector g_module_db; -const FunctionDef* GetSyscallInfo(u32 opcode) { +const FunctionDef* GetSVCInfo(u32 opcode) { u32 func_num = opcode & 0xFFFFFF; // 8 bits if (func_num > 0xFF) { - ERROR_LOG(HLE,"Unknown syscall: 0x%02X", func_num); + ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num); return NULL; } return &g_module_db[0].func_table[func_num]; } -void CallSyscall(u32 opcode) { - const FunctionDef *info = GetSyscallInfo(opcode); +void CallSVC(u32 opcode) { + const FunctionDef *info = GetSVCInfo(opcode); if (!info) { return; @@ -33,7 +33,7 @@ void CallSyscall(u32 opcode) { if (info->func) { info->func(); } else { - ERROR_LOG(HLE, "Unimplemented SysCall function %s(..)", info->name.c_str()); + ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str()); } } @@ -54,7 +54,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef* func } void RegisterAllModules() { - Syscall::Register(); + SVC::Register(); } void Init() { diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index 452546e1f8..c075147c39 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h @@ -34,7 +34,7 @@ struct ModuleDef { void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table); -void CallSyscall(u32 opcode); +void CallSVC(u32 opcode); void EatCycles(u32 cycles); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index cfc5327a3e..136fff0211 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -15,7 +15,7 @@ #include "core/core.h" #include "core/mem_map.h" #include "core/hle/hle.h" -#include "core/hle/syscall.h" +#include "core/hle/svc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index f334dbcb8e..eba730efb9 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -14,7 +14,7 @@ #include "core/mem_map.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/syscall.h" +#include "core/hle/svc.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp new file mode 100644 index 0000000000..a9141699c8 --- /dev/null +++ b/src/core/hle/svc.cpp @@ -0,0 +1,350 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "common/symbols.h" + +#include "core/mem_map.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/thread.h" + +#include "core/hle/function_wrappers.h" +#include "core/hle/svc.h" +#include "core/hle/service/service.h" +#include "core/hle/kernel/thread.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SVC + +namespace SVC { + +enum ControlMemoryOperation { + MEMORY_OPERATION_HEAP = 0x00000003, + MEMORY_OPERATION_GSP_HEAP = 0x00010003, +}; + +enum MapMemoryPermission { + MEMORY_PERMISSION_UNMAP = 0x00000000, + MEMORY_PERMISSION_NORMAL = 0x00000001, +}; + +/// Map application or GSP heap memory +Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { + u32* outaddr = (u32*)_outaddr; + u32 virtual_address = 0x00000000; + + DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", + operation, addr0, addr1, size, permissions); + + switch (operation) { + + // Map normal heap memory + case MEMORY_OPERATION_HEAP: + virtual_address = Memory::MapBlock_Heap(size, operation, permissions); + break; + + // Map GSP heap memory + case MEMORY_OPERATION_GSP_HEAP: + virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); + break; + + // Unknown ControlMemory operation + default: + ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); + } + if (NULL != outaddr) { + *outaddr = virtual_address; + } + Core::g_app_core->SetReg(1, virtual_address); + + return 0; +} + +/// Maps a memory block to specified address +Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { + DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", + memblock, addr, mypermissions, otherpermission); + switch (mypermissions) { + case MEMORY_PERMISSION_NORMAL: + case MEMORY_PERMISSION_NORMAL + 1: + case MEMORY_PERMISSION_NORMAL + 2: + Memory::MapBlock_Shared(memblock, addr, mypermissions); + break; + default: + ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); + } + return 0; +} + +/// Connect to an OS service given the port name, returns the handle to the port to out +Result ConnectToPort(void* out, const char* port_name) { + Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); + Core::g_app_core->SetReg(1, service->GetHandle()); + DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); + return 0; +} + +/// Synchronize to an OS service +Result SendSyncRequest(Handle handle) { + DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); + Service::Interface* service = Service::g_manager->FetchFromHandle(handle); + service->Sync(); + return 0; +} + +/// Close a handle +Result CloseHandle(Handle handle) { + // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); + return 0; +} + +/// Wait for a handle to synchronize, timeout after the specified nanoseconds +Result WaitSynchronization1(Handle handle, s64 nano_seconds) { + // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", + handle, nano_seconds); + return 0; +} + +/// Wait for the given handles to synchronize, timeout after the specified nanoseconds +Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { + s32* out = (s32*)_out; + Handle* handles = (Handle*)_handles; + // ImplementMe + + DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", + handle_count, (wait_all ? "true" : "false"), nano_seconds); + + for (u32 i = 0; i < handle_count; i++) { + DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); + } + __KernelReschedule("WaitSynchronizationN"); + + return 0; +} + +/// Create an address arbiter (to allocate access to shared resources) +Result CreateAddressArbiter(void* arbiter) { + // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); + Core::g_app_core->SetReg(1, 0xFABBDADD); + return 0; +} + +/// Used to output a message on a debug hardware unit - does nothing on a retail unit +void OutputDebugString(const char* string) { + NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); +} + +/// Get resource limit +Result GetResourceLimit(void* resource_limit, Handle process) { + // With regards to proceess values: + // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for + // the current KThread. + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); + Core::g_app_core->SetReg(1, 0xDEADBEEF); + return 0; +} + +/// Get resource limit current values +Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { + //s64* values = (s64*)_values; + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", + resource_limit, names, name_count); + Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now + return 0; +} + +Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top, + u32 processor_id) { + std::string name; + if (Symbols::HasSymbol(entry_point)) { + TSymbol symbol = Symbols::GetSymbol(entry_point); + name = symbol.name; + } else { + char buff[100]; + sprintf(buff, "%s", "unknown-%08X", entry_point); + name = buff; + } + DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " + "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top, + priority, processor_id); + + Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id, + stack_top); + Core::g_app_core->SetReg(1, 0xFEEDDEAF); + + return 0; +} + +Result CreateMutex(void* _mutex, u32 initial_locked) { + Handle* mutex = (Handle*)_mutex; + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s", + initial_locked ? "true" : "false"); + Core::g_app_core->SetReg(1, 0xF00D0BAD); + return 0; +} + +Result ReleaseMutex(Handle handle) { + DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle); + return 0; +} + +Result GetThreadId(void* thread_id, u32 thread) { + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); + return 0; +} + +Result QueryMemory(void *_info, void *_out, u32 addr) { + MemoryInfo* info = (MemoryInfo*) _info; + PageInfo* out = (PageInfo*) _out; + DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr); + return 0; +} + +Result CreateEvent(void* _event, u32 reset_type) { + Handle* event = (Handle*)_event; + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); + Core::g_app_core->SetReg(1, 0xBADC0DE0); + return 0; +} + +const HLE::FunctionDef SVC_Table[] = { + {0x00, NULL, "Unknown"}, + {0x01, WrapI_VUUUUU, "ControlMemory"}, + {0x02, WrapI_VVU, "QueryMemory"}, + {0x03, NULL, "ExitProcess"}, + {0x04, NULL, "GetProcessAffinityMask"}, + {0x05, NULL, "SetProcessAffinityMask"}, + {0x06, NULL, "GetProcessIdealProcessor"}, + {0x07, NULL, "SetProcessIdealProcessor"}, + {0x08, WrapI_VUUUUU, "CreateThread"}, + {0x09, NULL, "ExitThread"}, + {0x0A, NULL, "SleepThread"}, + {0x0B, NULL, "GetThreadPriority"}, + {0x0C, NULL, "SetThreadPriority"}, + {0x0D, NULL, "GetThreadAffinityMask"}, + {0x0E, NULL, "SetThreadAffinityMask"}, + {0x0F, NULL, "GetThreadIdealProcessor"}, + {0x10, NULL, "SetThreadIdealProcessor"}, + {0x11, NULL, "GetCurrentProcessorNumber"}, + {0x12, NULL, "Run"}, + {0x13, WrapI_VU, "CreateMutex"}, + {0x14, WrapI_U, "ReleaseMutex"}, + {0x15, NULL, "CreateSemaphore"}, + {0x16, NULL, "ReleaseSemaphore"}, + {0x17, WrapI_VU, "CreateEvent"}, + {0x18, NULL, "SignalEvent"}, + {0x19, NULL, "ClearEvent"}, + {0x1A, NULL, "CreateTimer"}, + {0x1B, NULL, "SetTimer"}, + {0x1C, NULL, "CancelTimer"}, + {0x1D, NULL, "ClearTimer"}, + {0x1E, NULL, "CreateMemoryBlock"}, + {0x1F, WrapI_UUUU, "MapMemoryBlock"}, + {0x20, NULL, "UnmapMemoryBlock"}, + {0x21, WrapI_V, "CreateAddressArbiter"}, + {0x22, NULL, "ArbitrateAddress"}, + {0x23, WrapI_U, "CloseHandle"}, + {0x24, WrapI_US64, "WaitSynchronization1"}, + {0x25, WrapI_VVUUS64, "WaitSynchronizationN"}, + {0x26, NULL, "SignalAndWait"}, + {0x27, NULL, "DuplicateHandle"}, + {0x28, NULL, "GetSystemTick"}, + {0x29, NULL, "GetHandleInfo"}, + {0x2A, NULL, "GetSystemInfo"}, + {0x2B, NULL, "GetProcessInfo"}, + {0x2C, NULL, "GetThreadInfo"}, + {0x2D, WrapI_VC, "ConnectToPort"}, + {0x2E, NULL, "SendSyncRequest1"}, + {0x2F, NULL, "SendSyncRequest2"}, + {0x30, NULL, "SendSyncRequest3"}, + {0x31, NULL, "SendSyncRequest4"}, + {0x32, WrapI_U, "SendSyncRequest"}, + {0x33, NULL, "OpenProcess"}, + {0x34, NULL, "OpenThread"}, + {0x35, NULL, "GetProcessId"}, + {0x36, NULL, "GetProcessIdOfThread"}, + {0x37, WrapI_VU, "GetThreadId"}, + {0x38, WrapI_VU, "GetResourceLimit"}, + {0x39, NULL, "GetResourceLimitLimitValues"}, + {0x3A, WrapI_VUVI, "GetResourceLimitCurrentValues"}, + {0x3B, NULL, "GetThreadContext"}, + {0x3C, NULL, "Break"}, + {0x3D, WrapV_C, "OutputDebugString"}, + {0x3E, NULL, "ControlPerformanceCounter"}, + {0x3F, NULL, "Unknown"}, + {0x40, NULL, "Unknown"}, + {0x41, NULL, "Unknown"}, + {0x42, NULL, "Unknown"}, + {0x43, NULL, "Unknown"}, + {0x44, NULL, "Unknown"}, + {0x45, NULL, "Unknown"}, + {0x46, NULL, "Unknown"}, + {0x47, NULL, "CreatePort"}, + {0x48, NULL, "CreateSessionToPort"}, + {0x49, NULL, "CreateSession"}, + {0x4A, NULL, "AcceptSession"}, + {0x4B, NULL, "ReplyAndReceive1"}, + {0x4C, NULL, "ReplyAndReceive2"}, + {0x4D, NULL, "ReplyAndReceive3"}, + {0x4E, NULL, "ReplyAndReceive4"}, + {0x4F, NULL, "ReplyAndReceive"}, + {0x50, NULL, "BindInterrupt"}, + {0x51, NULL, "UnbindInterrupt"}, + {0x52, NULL, "InvalidateProcessDataCache"}, + {0x53, NULL, "StoreProcessDataCache"}, + {0x54, NULL, "FlushProcessDataCache"}, + {0x55, NULL, "StartInterProcessDma"}, + {0x56, NULL, "StopDma"}, + {0x57, NULL, "GetDmaState"}, + {0x58, NULL, "RestartDma"}, + {0x59, NULL, "Unknown"}, + {0x5A, NULL, "Unknown"}, + {0x5B, NULL, "Unknown"}, + {0x5C, NULL, "Unknown"}, + {0x5D, NULL, "Unknown"}, + {0x5E, NULL, "Unknown"}, + {0x5F, NULL, "Unknown"}, + {0x60, NULL, "DebugActiveProcess"}, + {0x61, NULL, "BreakDebugProcess"}, + {0x62, NULL, "TerminateDebugProcess"}, + {0x63, NULL, "GetProcessDebugEvent"}, + {0x64, NULL, "ContinueDebugEvent"}, + {0x65, NULL, "GetProcessList"}, + {0x66, NULL, "GetThreadList"}, + {0x67, NULL, "GetDebugThreadContext"}, + {0x68, NULL, "SetDebugThreadContext"}, + {0x69, NULL, "QueryDebugProcessMemory"}, + {0x6A, NULL, "ReadProcessMemory"}, + {0x6B, NULL, "WriteProcessMemory"}, + {0x6C, NULL, "SetHardwareBreakPoint"}, + {0x6D, NULL, "GetDebugThreadParam"}, + {0x6E, NULL, "Unknown"}, + {0x6F, NULL, "Unknown"}, + {0x70, NULL, "ControlProcessMemory"}, + {0x71, NULL, "MapProcessMemory"}, + {0x72, NULL, "UnmapProcessMemory"}, + {0x73, NULL, "Unknown"}, + {0x74, NULL, "Unknown"}, + {0x75, NULL, "Unknown"}, + {0x76, NULL, "TerminateProcess"}, + {0x77, NULL, "Unknown"}, + {0x78, NULL, "CreateResourceLimit"}, + {0x79, NULL, "Unknown"}, + {0x7A, NULL, "Unknown"}, + {0x7B, NULL, "Unknown"}, + {0x7C, NULL, "KernelSetState"}, + {0x7D, NULL, "QueryProcessMemory"}, +}; + +void Register() { + HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table); +} + +} // namespace diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h new file mode 100644 index 0000000000..5c35977d13 --- /dev/null +++ b/src/core/hle/svc.h @@ -0,0 +1,48 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SVC types + +struct MemoryInfo { + u32 base_address; + u32 size; + u32 permission; + u32 state; +}; + +struct PageInfo { + u32 flags; +}; + +struct ThreadContext { + u32 cpu_registers[13]; + u32 sp; + u32 lr; + u32 pc; + u32 cpsr; + u32 fpu_registers[32]; + u32 fpscr; + u32 fpexc; +}; + +enum ResetType { + RESETTYPE_ONESHOT, + RESETTYPE_STICKY, + RESETTYPE_PULSE, + RESETTYPE_MAX_BIT = (1u << 31), +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SVC + +namespace SVC { + +void Register(); + +} // namespace diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp deleted file mode 100644 index 9a12352468..0000000000 --- a/src/core/hle/syscall.cpp +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include - -#include "common/symbols.h" - -#include "core/mem_map.h" - -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/thread.h" - -#include "core/hle/function_wrappers.h" -#include "core/hle/syscall.h" -#include "core/hle/service/service.h" -#include "core/hle/kernel/thread.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace Syscall - -namespace Syscall { - -enum ControlMemoryOperation { - MEMORY_OPERATION_HEAP = 0x00000003, - MEMORY_OPERATION_GSP_HEAP = 0x00010003, -}; - -enum MapMemoryPermission { - MEMORY_PERMISSION_UNMAP = 0x00000000, - MEMORY_PERMISSION_NORMAL = 0x00000001, -}; - -/// Map application or GSP heap memory -Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { - u32* outaddr = (u32*)_outaddr; - u32 virtual_address = 0x00000000; - - DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", - operation, addr0, addr1, size, permissions); - - switch (operation) { - - // Map normal heap memory - case MEMORY_OPERATION_HEAP: - virtual_address = Memory::MapBlock_Heap(size, operation, permissions); - break; - - // Map GSP heap memory - case MEMORY_OPERATION_GSP_HEAP: - virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); - break; - - // Unknown ControlMemory operation - default: - ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); - } - if (NULL != outaddr) { - *outaddr = virtual_address; - } - Core::g_app_core->SetReg(1, virtual_address); - - return 0; -} - -/// Maps a memory block to specified address -Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { - DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", - memblock, addr, mypermissions, otherpermission); - switch (mypermissions) { - case MEMORY_PERMISSION_NORMAL: - case MEMORY_PERMISSION_NORMAL + 1: - case MEMORY_PERMISSION_NORMAL + 2: - Memory::MapBlock_Shared(memblock, addr, mypermissions); - break; - default: - ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); - } - return 0; -} - -/// Connect to an OS service given the port name, returns the handle to the port to out -Result ConnectToPort(void* out, const char* port_name) { - Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); - Core::g_app_core->SetReg(1, service->GetHandle()); - DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); - return 0; -} - -/// Synchronize to an OS service -Result SendSyncRequest(Handle handle) { - DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); - Service::Interface* service = Service::g_manager->FetchFromHandle(handle); - service->Sync(); - return 0; -} - -/// Close a handle -Result CloseHandle(Handle handle) { - // ImplementMe - DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); - return 0; -} - -/// Wait for a handle to synchronize, timeout after the specified nanoseconds -Result WaitSynchronization1(Handle handle, s64 nano_seconds) { - // ImplementMe - DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", - handle, nano_seconds); - return 0; -} - -/// Wait for the given handles to synchronize, timeout after the specified nanoseconds -Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { - s32* out = (s32*)_out; - Handle* handles = (Handle*)_handles; - // ImplementMe - - DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", - handle_count, (wait_all ? "true" : "false"), nano_seconds); - - for (u32 i = 0; i < handle_count; i++) { - DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); - } - return 0; -} - -/// Create an address arbiter (to allocate access to shared resources) -Result CreateAddressArbiter(void* arbiter) { - // ImplementMe - DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); - Core::g_app_core->SetReg(1, 0xFABBDADD); - return 0; -} - -/// Used to output a message on a debug hardware unit - does nothing on a retail unit -void OutputDebugString(const char* string) { - NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); -} - -/// Get resource limit -Result GetResourceLimit(void* resource_limit, Handle process) { - // With regards to proceess values: - // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for - // the current KThread. - DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); - Core::g_app_core->SetReg(1, 0xDEADBEEF); - return 0; -} - -/// Get resource limit current values -Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { - //s64* values = (s64*)_values; - DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", - resource_limit, names, name_count); - Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now - return 0; -} - -Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top, - u32 processor_id) { - std::string name; - if (Symbols::HasSymbol(entry_point)) { - TSymbol symbol = Symbols::GetSymbol(entry_point); - name = symbol.name; - } else { - char buff[100]; - sprintf(buff, "%s", "unknown-%08X", entry_point); - name = buff; - } - DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " - "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top, - priority, processor_id); - - Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id, - stack_top); - Core::g_app_core->SetReg(1, 0xFEEDDEAF); - - return 0; -} - -Result CreateMutex(void* _mutex, u32 initial_locked) { - Handle* mutex = (Handle*)_mutex; - DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s", - initial_locked ? "true" : "false"); - Core::g_app_core->SetReg(1, 0xF00D0BAD); - return 0; -} - -Result ReleaseMutex(Handle handle) { - DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle); - return 0; -} - -Result GetThreadId(void* thread_id, u32 thread) { - DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); - return 0; -} - -Result QueryMemory(void *_info, void *_out, u32 addr) { - MemoryInfo* info = (MemoryInfo*) _info; - PageInfo* out = (PageInfo*) _out; - DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr); - return 0; -} - -Result CreateEvent(void* _event, u32 reset_type) { - Handle* event = (Handle*)_event; - DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); - Core::g_app_core->SetReg(1, 0xBADC0DE0); - return 0; -} - -const HLE::FunctionDef Syscall_Table[] = { - {0x00, NULL, "Unknown"}, - {0x01, WrapI_VUUUUU, "ControlMemory"}, - {0x02, WrapI_VVU, "QueryMemory"}, - {0x03, NULL, "ExitProcess"}, - {0x04, NULL, "GetProcessAffinityMask"}, - {0x05, NULL, "SetProcessAffinityMask"}, - {0x06, NULL, "GetProcessIdealProcessor"}, - {0x07, NULL, "SetProcessIdealProcessor"}, - {0x08, WrapI_VUUUUU, "CreateThread"}, - {0x09, NULL, "ExitThread"}, - {0x0A, NULL, "SleepThread"}, - {0x0B, NULL, "GetThreadPriority"}, - {0x0C, NULL, "SetThreadPriority"}, - {0x0D, NULL, "GetThreadAffinityMask"}, - {0x0E, NULL, "SetThreadAffinityMask"}, - {0x0F, NULL, "GetThreadIdealProcessor"}, - {0x10, NULL, "SetThreadIdealProcessor"}, - {0x11, NULL, "GetCurrentProcessorNumber"}, - {0x12, NULL, "Run"}, - {0x13, WrapI_VU, "CreateMutex"}, - {0x14, WrapI_U, "ReleaseMutex"}, - {0x15, NULL, "CreateSemaphore"}, - {0x16, NULL, "ReleaseSemaphore"}, - {0x17, WrapI_VU, "CreateEvent"}, - {0x18, NULL, "SignalEvent"}, - {0x19, NULL, "ClearEvent"}, - {0x1A, NULL, "CreateTimer"}, - {0x1B, NULL, "SetTimer"}, - {0x1C, NULL, "CancelTimer"}, - {0x1D, NULL, "ClearTimer"}, - {0x1E, NULL, "CreateMemoryBlock"}, - {0x1F, WrapI_UUUU, "MapMemoryBlock"}, - {0x20, NULL, "UnmapMemoryBlock"}, - {0x21, WrapI_V, "CreateAddressArbiter"}, - {0x22, NULL, "ArbitrateAddress"}, - {0x23, WrapI_U, "CloseHandle"}, - {0x24, WrapI_US64, "WaitSynchronization1"}, - {0x25, WrapI_VVUUS64, "WaitSynchronizationN"}, - {0x26, NULL, "SignalAndWait"}, - {0x27, NULL, "DuplicateHandle"}, - {0x28, NULL, "GetSystemTick"}, - {0x29, NULL, "GetHandleInfo"}, - {0x2A, NULL, "GetSystemInfo"}, - {0x2B, NULL, "GetProcessInfo"}, - {0x2C, NULL, "GetThreadInfo"}, - {0x2D, WrapI_VC, "ConnectToPort"}, - {0x2E, NULL, "SendSyncRequest1"}, - {0x2F, NULL, "SendSyncRequest2"}, - {0x30, NULL, "SendSyncRequest3"}, - {0x31, NULL, "SendSyncRequest4"}, - {0x32, WrapI_U, "SendSyncRequest"}, - {0x33, NULL, "OpenProcess"}, - {0x34, NULL, "OpenThread"}, - {0x35, NULL, "GetProcessId"}, - {0x36, NULL, "GetProcessIdOfThread"}, - {0x37, WrapI_VU, "GetThreadId"}, - {0x38, WrapI_VU, "GetResourceLimit"}, - {0x39, NULL, "GetResourceLimitLimitValues"}, - {0x3A, WrapI_VUVI, "GetResourceLimitCurrentValues"}, - {0x3B, NULL, "GetThreadContext"}, - {0x3C, NULL, "Break"}, - {0x3D, WrapV_C, "OutputDebugString"}, - {0x3E, NULL, "ControlPerformanceCounter"}, - {0x3F, NULL, "Unknown"}, - {0x40, NULL, "Unknown"}, - {0x41, NULL, "Unknown"}, - {0x42, NULL, "Unknown"}, - {0x43, NULL, "Unknown"}, - {0x44, NULL, "Unknown"}, - {0x45, NULL, "Unknown"}, - {0x46, NULL, "Unknown"}, - {0x47, NULL, "CreatePort"}, - {0x48, NULL, "CreateSessionToPort"}, - {0x49, NULL, "CreateSession"}, - {0x4A, NULL, "AcceptSession"}, - {0x4B, NULL, "ReplyAndReceive1"}, - {0x4C, NULL, "ReplyAndReceive2"}, - {0x4D, NULL, "ReplyAndReceive3"}, - {0x4E, NULL, "ReplyAndReceive4"}, - {0x4F, NULL, "ReplyAndReceive"}, - {0x50, NULL, "BindInterrupt"}, - {0x51, NULL, "UnbindInterrupt"}, - {0x52, NULL, "InvalidateProcessDataCache"}, - {0x53, NULL, "StoreProcessDataCache"}, - {0x54, NULL, "FlushProcessDataCache"}, - {0x55, NULL, "StartInterProcessDma"}, - {0x56, NULL, "StopDma"}, - {0x57, NULL, "GetDmaState"}, - {0x58, NULL, "RestartDma"}, - {0x59, NULL, "Unknown"}, - {0x5A, NULL, "Unknown"}, - {0x5B, NULL, "Unknown"}, - {0x5C, NULL, "Unknown"}, - {0x5D, NULL, "Unknown"}, - {0x5E, NULL, "Unknown"}, - {0x5F, NULL, "Unknown"}, - {0x60, NULL, "DebugActiveProcess"}, - {0x61, NULL, "BreakDebugProcess"}, - {0x62, NULL, "TerminateDebugProcess"}, - {0x63, NULL, "GetProcessDebugEvent"}, - {0x64, NULL, "ContinueDebugEvent"}, - {0x65, NULL, "GetProcessList"}, - {0x66, NULL, "GetThreadList"}, - {0x67, NULL, "GetDebugThreadContext"}, - {0x68, NULL, "SetDebugThreadContext"}, - {0x69, NULL, "QueryDebugProcessMemory"}, - {0x6A, NULL, "ReadProcessMemory"}, - {0x6B, NULL, "WriteProcessMemory"}, - {0x6C, NULL, "SetHardwareBreakPoint"}, - {0x6D, NULL, "GetDebugThreadParam"}, - {0x6E, NULL, "Unknown"}, - {0x6F, NULL, "Unknown"}, - {0x70, NULL, "ControlProcessMemory"}, - {0x71, NULL, "MapProcessMemory"}, - {0x72, NULL, "UnmapProcessMemory"}, - {0x73, NULL, "Unknown"}, - {0x74, NULL, "Unknown"}, - {0x75, NULL, "Unknown"}, - {0x76, NULL, "TerminateProcess"}, - {0x77, NULL, "Unknown"}, - {0x78, NULL, "CreateResourceLimit"}, - {0x79, NULL, "Unknown"}, - {0x7A, NULL, "Unknown"}, - {0x7B, NULL, "Unknown"}, - {0x7C, NULL, "KernelSetState"}, - {0x7D, NULL, "QueryProcessMemory"}, -}; - -void Register() { - HLE::RegisterModule("SyscallTable", ARRAY_SIZE(Syscall_Table), Syscall_Table); -} - -} // namespace diff --git a/src/core/hle/syscall.h b/src/core/hle/syscall.h deleted file mode 100644 index 3da349ed5f..0000000000 --- a/src/core/hle/syscall.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// SVC types - -struct MemoryInfo { - u32 base_address; - u32 size; - u32 permission; - u32 state; -}; - -struct PageInfo { - u32 flags; -}; - -struct ThreadContext { - u32 cpu_registers[13]; - u32 sp; - u32 lr; - u32 pc; - u32 cpsr; - u32 fpu_registers[32]; - u32 fpscr; - u32 fpexc; -}; - -enum ResetType { - RESETTYPE_ONESHOT, - RESETTYPE_STICKY, - RESETTYPE_PULSE, - RESETTYPE_MAX_BIT = (1u << 31), -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace Syscall - -namespace Syscall { - -void Register(); - -} // namespace -- cgit v1.2.3 From 49dc2ce8ac4fc37a008fa28e0771c8c74c576b05 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 18:50:16 -0400 Subject: ARM_Interface: added SaveContext and LoadContext functions for HLE thread switching --- src/core/arm/arm_interface.h | 16 +++++++++++- src/core/arm/interpreter/arm_interpreter.cpp | 36 ++++++++++++++++++++++++++ src/core/arm/interpreter/arm_interpreter.h | 12 +++++++++ src/core/hle/kernel/thread.cpp | 38 ++-------------------------- 4 files changed, 65 insertions(+), 37 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 5c382ebbdd..52bc82115f 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -7,6 +7,8 @@ #include "common/common.h" #include "common/common_types.h" +#include "core/hle/svc.h" + /// Generic ARM11 CPU interface class ARM_Interface : NonCopyable { public: @@ -75,6 +77,18 @@ public: */ virtual u64 GetTicks() const = 0; + /** + * Saves the current CPU context + * @param ctx Thread context to save + */ + virtual void SaveContext(ThreadContext& ctx) = 0; + + /** + * Loads a CPU context + * @param ctx Thread context to load + */ + virtual void LoadContext(const ThreadContext& ctx) = 0; + /// Getter for m_num_instructions u64 GetNumInstructions() { return m_num_instructions; @@ -90,6 +104,6 @@ protected: private: - u64 m_num_instructions; ///< Number of instructions executed + u64 m_num_instructions; ///< Number of instructions executed }; diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index c21ff04649..b8c46cdfca 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp @@ -101,3 +101,39 @@ void ARM_Interpreter::ExecuteInstructions(int num_instructions) { m_state->NumInstrsToExecute = num_instructions; ARMul_Emulate32(m_state); } + +/** + * Saves the current CPU context + * @param ctx Thread context to save + * @todo Do we need to save Reg[15] and NextInstr? + */ +void ARM_Interpreter::SaveContext(ThreadContext& ctx) { + memcpy(ctx.cpu_registers, m_state->Reg, sizeof(ctx.cpu_registers)); + memcpy(ctx.fpu_registers, m_state->ExtReg, sizeof(ctx.fpu_registers)); + + ctx.sp = m_state->Reg[13]; + ctx.lr = m_state->Reg[14]; + ctx.pc = m_state->pc; + ctx.cpsr = m_state->Cpsr; + + ctx.fpscr = m_state->VFP[1]; + ctx.fpexc = m_state->VFP[2]; +} + +/** + * Loads a CPU context + * @param ctx Thread context to load + * @param Do we need to load Reg[15] and NextInstr? + */ +void ARM_Interpreter::LoadContext(const ThreadContext& ctx) { + memcpy(m_state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); + memcpy(m_state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); + + m_state->Reg[13] = ctx.sp; + m_state->Reg[14] = ctx.lr; + m_state->pc = ctx.pc; + m_state->Cpsr = ctx.cpsr; + + m_state->VFP[1] = ctx.fpscr; + m_state->VFP[2] = ctx.fpexc; +} diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index 474ba3e450..15240568c2 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h @@ -60,6 +60,18 @@ public: */ u64 GetTicks() const; + /** + * Saves the current CPU context + * @param ctx Thread context to save + */ + void SaveContext(ThreadContext& ctx); + + /** + * Loads a CPU context + * @param ctx Thread context to load + */ + void LoadContext(const ThreadContext& ctx); + protected: /** diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 136fff0211..b3d306c531 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -98,46 +98,12 @@ inline void __SetCurrentThread(Thread* t) { /// Saves the current CPU context void __KernelSaveContext(ThreadContext& ctx) { - ctx.cpu_registers[0] = Core::g_app_core->GetReg(0); - ctx.cpu_registers[1] = Core::g_app_core->GetReg(1); - ctx.cpu_registers[2] = Core::g_app_core->GetReg(2); - ctx.cpu_registers[3] = Core::g_app_core->GetReg(3); - ctx.cpu_registers[4] = Core::g_app_core->GetReg(4); - ctx.cpu_registers[5] = Core::g_app_core->GetReg(5); - ctx.cpu_registers[6] = Core::g_app_core->GetReg(6); - ctx.cpu_registers[7] = Core::g_app_core->GetReg(7); - ctx.cpu_registers[8] = Core::g_app_core->GetReg(8); - ctx.cpu_registers[9] = Core::g_app_core->GetReg(9); - ctx.cpu_registers[10] = Core::g_app_core->GetReg(10); - ctx.cpu_registers[11] = Core::g_app_core->GetReg(11); - ctx.cpu_registers[12] = Core::g_app_core->GetReg(12); - ctx.sp = Core::g_app_core->GetReg(13); - ctx.lr = Core::g_app_core->GetReg(14); - ctx.pc = Core::g_app_core->GetPC(); - ctx.cpsr = Core::g_app_core->GetCPSR(); + Core::g_app_core->SaveContext(ctx); } /// Loads a CPU context void __KernelLoadContext(const ThreadContext& ctx) { - Core::g_app_core->SetReg(0, ctx.cpu_registers[0]); - Core::g_app_core->SetReg(1, ctx.cpu_registers[1]); - Core::g_app_core->SetReg(2, ctx.cpu_registers[2]); - Core::g_app_core->SetReg(3, ctx.cpu_registers[3]); - Core::g_app_core->SetReg(4, ctx.cpu_registers[4]); - Core::g_app_core->SetReg(5, ctx.cpu_registers[5]); - Core::g_app_core->SetReg(6, ctx.cpu_registers[6]); - Core::g_app_core->SetReg(7, ctx.cpu_registers[7]); - Core::g_app_core->SetReg(8, ctx.cpu_registers[8]); - Core::g_app_core->SetReg(9, ctx.cpu_registers[9]); - Core::g_app_core->SetReg(10, ctx.cpu_registers[10]); - Core::g_app_core->SetReg(11, ctx.cpu_registers[11]); - Core::g_app_core->SetReg(12, ctx.cpu_registers[12]); - Core::g_app_core->SetReg(13, ctx.sp); - Core::g_app_core->SetReg(14, ctx.lr); - //Core::g_app_core->SetReg(15, ctx.pc); - - Core::g_app_core->SetPC(ctx.pc); - Core::g_app_core->SetCPSR(ctx.cpsr); + Core::g_app_core->LoadContext(ctx); } /// Resets a thread -- cgit v1.2.3 From 75c6d2a8fa3547946227094af6c179e5ccba0e1e Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 19:37:46 -0400 Subject: thread: moved threading calls to the Kernel namespace --- src/core/hle/kernel/kernel.cpp | 6 +- src/core/hle/kernel/thread.cpp | 184 +++++++++++++++++++++-------------------- src/core/hle/kernel/thread.h | 26 ++++-- src/core/hle/svc.cpp | 4 +- 4 files changed, 117 insertions(+), 103 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b1fdffde5e..45e36173c0 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -132,11 +132,11 @@ Object* ObjectPool::CreateByIDType(int type) { } void Init() { - __KernelThreadingInit(); + Kernel::ThreadingInit(); } void Shutdown() { - __KernelThreadingShutdown(); + Kernel::ThreadingShutdown(); } } // namespace @@ -147,7 +147,7 @@ bool __KernelLoadExec(u32 entry_point) { Core::g_app_core->SetPC(entry_point); // 0x30 is the typical main thread priority I've seen used so far - Handle thread_id = __KernelSetupMainThread(0x30); + Handle thread_id = Kernel::SetupMainThread(0x30); return true; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b3d306c531..7b4f0ea47d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -19,7 +19,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -// Enums +namespace Kernel { enum ThreadStatus { THREADSTATUS_RUNNING = 1, @@ -81,33 +81,32 @@ std::vector g_thread_queue; Common::ThreadQueueList g_thread_ready_queue; Handle g_current_thread_handle; - Thread* g_current_thread; +/// Gets the current thread inline Thread* __GetCurrentThread() { return g_current_thread; } +/// Sets the current thread inline void __SetCurrentThread(Thread* t) { g_current_thread = t; g_current_thread_handle = t->GetHandle(); } -//////////////////////////////////////////////////////////////////////////////////////////////////// - /// Saves the current CPU context -void __KernelSaveContext(ThreadContext& ctx) { +void __SaveContext(ThreadContext& ctx) { Core::g_app_core->SaveContext(ctx); } /// Loads a CPU context -void __KernelLoadContext(const ThreadContext& ctx) { +void __LoadContext(const ThreadContext& ctx) { Core::g_app_core->LoadContext(ctx); } /// Resets a thread -void __KernelResetThread(Thread* t, s32 lowest_priority) { +void __ResetThread(Thread* t, s32 lowest_priority) { memset(&t->context, 0, sizeof(ThreadContext)); t->context.pc = t->entry_point; @@ -121,7 +120,7 @@ void __KernelResetThread(Thread* t, s32 lowest_priority) { } /// Change a thread to "ready" state -void __KernelChangeReadyState(Thread* t, bool ready) { +void __ChangeReadyState(Thread* t, bool ready) { Handle handle = t->GetHandle(); if (t->IsReady()) { if (!ready) { @@ -138,11 +137,11 @@ void __KernelChangeReadyState(Thread* t, bool ready) { } /// Changes a threads state -void __KernelChangeThreadState(Thread* t, ThreadStatus new_status) { +void __ChangeThreadState(Thread* t, ThreadStatus new_status) { if (!t || t->status == new_status) { return; } - __KernelChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); + __ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); t->status = new_status; if (new_status == THREADSTATUS_WAIT) { @@ -153,16 +152,75 @@ void __KernelChangeThreadState(Thread* t, ThreadStatus new_status) { } /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) -void __KernelCallThread(Thread* t) { +void __CallThread(Thread* t) { // Stop waiting if (t->wait_type != WAITTYPE_NONE) { t->wait_type = WAITTYPE_NONE; } - __KernelChangeThreadState(t, THREADSTATUS_READY); + __ChangeThreadState(t, THREADSTATUS_READY); +} + +/// Switches CPU context to that of the specified thread +void __SwitchContext(Thread* t, const char* reason) { + Thread* cur = __GetCurrentThread(); + + // Save context for current thread + if (cur) { + __SaveContext(cur->context); + + if (cur->IsRunning()) { + __ChangeReadyState(cur, true); + } + } + // Load context of new thread + if (t) { + __SetCurrentThread(t); + __ChangeReadyState(t, false); + t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; + t->wait_type = WAITTYPE_NONE; + __LoadContext(t->context); + } else { + __SetCurrentThread(NULL); + } +} + +/// Gets the next thread that is ready to be run by priority +Thread* __NextThread() { + Handle next; + Thread* cur = __GetCurrentThread(); + + if (cur && cur->IsRunning()) { + next = g_thread_ready_queue.pop_first_better(cur->current_priority); + } else { + next = g_thread_ready_queue.pop_first(); + } + if (next < 0) { + return NULL; + } + return Kernel::g_object_pool.GetFast(next); +} + +/// Resumes a thread from waiting by marking it as "ready" +void __ResumeThreadFromWait(Handle handle) { + u32 error; + Thread* t = Kernel::g_object_pool.Get(handle, error); + if (t) { + t->status &= ~THREADSTATUS_WAIT; + if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { + __ChangeReadyState(t, true); + } + } +} + +/// Puts a thread in the wait state for the given type/reason +void __WaitCurThread(WaitType wait_type, const char* reason) { + Thread* t = __GetCurrentThread(); + t->wait_type = wait_type; + __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); } /// Creates a new thread -Thread* __KernelCreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, +Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { Thread* t = new Thread; @@ -187,31 +245,31 @@ Thread* __KernelCreateThread(Handle& handle, const char* name, u32 entry_point, } /// Creates a new thread - wrapper for external user -Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, +Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { if (name == NULL) { - ERROR_LOG(KERNEL, "__KernelCreateThread(): NULL name"); + ERROR_LOG(KERNEL, "CreateThread(): NULL name"); return -1; } if ((u32)stack_size < 0x200) { - ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid stack_size=0x%08X", name, + ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, stack_size); return -1; } if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); - WARN_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid priority=0x%08X, clamping to %08X", + WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X", name, priority, new_priority); // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm // validity of this priority = new_priority; } if (!Memory::GetPointer(entry_point)) { - ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid entry %08x", name, entry_point); + ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point); return -1; } Handle handle; - Thread* t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top, + Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, stack_size); HLE::EatCycles(32000); @@ -220,114 +278,62 @@ Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, s32 // Technically, this should not eat all at once, and reschedule in the middle, but that's hard. HLE::ReSchedule("thread created"); - __KernelCallThread(t); + __CallThread(t); return handle; } -/// Switches CPU context to that of the specified thread -void __KernelSwitchContext(Thread* t, const char* reason) { - Thread* cur = __GetCurrentThread(); - - // Save context for current thread - if (cur) { - __KernelSaveContext(cur->context); - - if (cur->IsRunning()) { - __KernelChangeReadyState(cur, true); - } - } - // Load context of new thread - if (t) { - __SetCurrentThread(t); - __KernelChangeReadyState(t, false); - t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; - t->wait_type = WAITTYPE_NONE; - __KernelLoadContext(t->context); - } else { - __SetCurrentThread(NULL); - } -} - -/// Gets the next thread that is ready to be run by priority -Thread* __KernelNextThread() { - Handle next; - Thread* cur = __GetCurrentThread(); - - if (cur && cur->IsRunning()) { - next = g_thread_ready_queue.pop_first_better(cur->current_priority); - } else { - next = g_thread_ready_queue.pop_first(); - } - if (next < 0) { - return NULL; - } - return Kernel::g_object_pool.GetFast(next); +/// Gets the current thread +Handle GetCurrentThread() { + return __GetCurrentThread()->GetHandle(); } /// Sets up the primary application thread -Handle __KernelSetupMainThread(s32 priority, int stack_size) { +Handle SetupMainThread(s32 priority, int stack_size) { Handle handle; // Initialize new "main" thread - Thread* t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority, + Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); - __KernelResetThread(t, 0); + __ResetThread(t, 0); // If running another thread already, set it to "ready" state Thread* cur = __GetCurrentThread(); if (cur && cur->IsRunning()) { - __KernelChangeReadyState(cur, true); + __ChangeReadyState(cur, true); } // Run new "main" thread __SetCurrentThread(t); t->status = THREADSTATUS_RUNNING; - __KernelLoadContext(t->context); + __LoadContext(t->context); return handle; } -/// Resumes a thread from waiting by marking it as "ready" -void __KernelResumeThreadFromWait(Handle handle) { - u32 error; - Thread* t = Kernel::g_object_pool.Get(handle, error); - if (t) { - t->status &= ~THREADSTATUS_WAIT; - if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { - __KernelChangeReadyState(t, true); - } - } -} - -/// Puts a thread in the wait state for the given type/reason -void __KernelWaitCurThread(WaitType wait_type, const char* reason) { - Thread* t = __GetCurrentThread(); - t->wait_type = wait_type; - __KernelChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); -} - /// Reschedules to the next available thread (call after current thread is suspended) -void __KernelReschedule(const char* reason) { - Thread* next = __KernelNextThread(); +void Reschedule(const char* reason) { + Thread* next = __NextThread(); if (next > 0) { - __KernelSwitchContext(next, reason); + __SwitchContext(next, reason); } } //////////////////////////////////////////////////////////////////////////////////////////////////// /// Put current thread in a wait state - on WaitSynchronization -void __KernelWaitThread_Synchronization() { +void WaitThread_Synchronization() { // TODO(bunnei): Just a placeholder function for now... FixMe - __KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called"); + __WaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called"); } //////////////////////////////////////////////////////////////////////////////////////////////////// -void __KernelThreadingInit() { +void ThreadingInit() { } -void __KernelThreadingShutdown() { +void ThreadingShutdown() { } + +} // namespace diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 72e9a416de..2c01992730 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -7,8 +7,6 @@ #include "common/common_types.h" #include "core/hle/kernel/kernel.h" -class Thread; - enum ThreadPriority { THREADPRIO_HIGHEST = 0, THREADPRIO_DEFAULT = 16, @@ -21,18 +19,28 @@ enum ThreadProcessorId { THREADPROCESSORID_ALL = 0xFFFFFFFC, }; +namespace Kernel { + /// Creates a new thread - wrapper for external user -Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, - s32 processor_id, u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); +Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, + u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Sets up the primary application thread -Handle __KernelSetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); +Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) -void __KernelReschedule(const char* reason); +void Reschedule(const char* reason); -void __KernelThreadingInit(); -void __KernelThreadingShutdown(); +/// Gets the current thread +Handle GetCurrentThread(); /// Put current thread in a wait state - on WaitSynchronization -void __KernelWaitThread_Synchronization(); +void WaitThread_Synchronization(); + +/// Initialize threading +void ThreadingInit(); + +/// Shutdown threading +void ThreadingShutdown(); + +} // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index a9141699c8..6f0f099c68 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -123,7 +123,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa for (u32 i = 0; i < handle_count; i++) { DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); } - __KernelReschedule("WaitSynchronizationN"); + Kernel::Reschedule("WaitSynchronizationN"); return 0; } @@ -175,7 +175,7 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top, priority, processor_id); - Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id, + Handle handle = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id, stack_top); Core::g_app_core->SetReg(1, 0xFEEDDEAF); -- cgit v1.2.3 From bed4e920fa17c6ab1e1cfde1f3ee81d0ca4aaff9 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 21:00:10 -0400 Subject: thread: exposed ResumeThreadFromWait function for use in other kernel modules --- src/core/hle/kernel/thread.cpp | 16 ++++++++-------- src/core/hle/kernel/thread.h | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 7b4f0ea47d..af9188faa3 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -200,8 +200,15 @@ Thread* __NextThread() { return Kernel::g_object_pool.GetFast(next); } +/// Puts a thread in the wait state for the given type/reason +void __WaitCurThread(WaitType wait_type, const char* reason) { + Thread* t = __GetCurrentThread(); + t->wait_type = wait_type; + __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); +} + /// Resumes a thread from waiting by marking it as "ready" -void __ResumeThreadFromWait(Handle handle) { +void ResumeThreadFromWait(Handle handle) { u32 error; Thread* t = Kernel::g_object_pool.Get(handle, error); if (t) { @@ -212,13 +219,6 @@ void __ResumeThreadFromWait(Handle handle) { } } -/// Puts a thread in the wait state for the given type/reason -void __WaitCurThread(WaitType wait_type, const char* reason) { - Thread* t = __GetCurrentThread(); - t->wait_type = wait_type; - __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); -} - /// Creates a new thread Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 2c01992730..bb48ddc79b 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -31,6 +31,9 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) void Reschedule(const char* reason); +/// Resumes a thread from waiting by marking it as "ready" +void ResumeThreadFromWait(Handle handle); + /// Gets the current thread Handle GetCurrentThread(); -- cgit v1.2.3 From 203541da119cad61096fda20b3ff8a8cb5906fd6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 May 2014 21:02:35 -0400 Subject: thread: added correct lowest thread priority, added a thread priority check, and added some comments --- src/core/hle/kernel/thread.cpp | 3 +++ src/core/hle/kernel/thread.h | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index af9188faa3..294e03ca62 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -223,6 +223,9 @@ void ResumeThreadFromWait(Handle handle) { Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { + _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), + "CreateThread priority=%d, outside of allowable range!", priority) + Thread* t = new Thread; handle = Kernel::g_object_pool.Create(t); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index bb48ddc79b..0d1fe19bf2 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -8,15 +8,16 @@ #include "core/hle/kernel/kernel.h" enum ThreadPriority { - THREADPRIO_HIGHEST = 0, - THREADPRIO_DEFAULT = 16, - THREADPRIO_LOWEST = 31, + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_DEFAULT = 16, ///< Default thread priority for userland apps + THREADPRIO_LOW = 31, ///< Low range of thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Thread priority max checked by svcCreateThread }; enum ThreadProcessorId { - THREADPROCESSORID_0 = 0xFFFFFFFE, - THREADPROCESSORID_1 = 0xFFFFFFFD, - THREADPROCESSORID_ALL = 0xFFFFFFFC, + THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode + THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore + THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores }; namespace Kernel { -- cgit v1.2.3 From 6a78be5930fd5eabbea740a5cf17efa5a7f1bc98 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 21 May 2014 21:42:18 -0400 Subject: thread: fixed bug where result of __NextThread was not being properly checked when NULL --- src/core/hle/kernel/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 294e03ca62..ef705e327d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -194,7 +194,7 @@ Thread* __NextThread() { } else { next = g_thread_ready_queue.pop_first(); } - if (next < 0) { + if (next == 0) { return NULL; } return Kernel::g_object_pool.GetFast(next); -- cgit v1.2.3 From 14bd37c5dc67c7777d4bea8d996bf2dfd8c7bdcc Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 22 May 2014 18:50:36 -0400 Subject: thread: moved ThreadStatus/WaitType to header, added support for arg on CreateThread, added correct CPSR reset --- src/core/hle/kernel/thread.cpp | 49 +++++++++++++----------------------------- src/core/hle/kernel/thread.h | 26 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 35 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ef705e327d..934ca87c4d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -21,27 +21,6 @@ namespace Kernel { -enum ThreadStatus { - THREADSTATUS_RUNNING = 1, - THREADSTATUS_READY = 2, - THREADSTATUS_WAIT = 4, - THREADSTATUS_SUSPEND = 8, - THREADSTATUS_DORMANT = 16, - THREADSTATUS_DEAD = 32, - THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND -}; - -enum WaitType { - WAITTYPE_NONE, - WAITTYPE_SLEEP, - WAITTYPE_SEMA, - WAITTYPE_EVENTFLAG, - WAITTYPE_THREADEND, - WAITTYPE_VBLANK, - WAITTYPE_MUTEX, - WAITTYPE_SYNCH, -}; - class Thread : public Kernel::Object { public: @@ -101,16 +80,18 @@ void __SaveContext(ThreadContext& ctx) { } /// Loads a CPU context -void __LoadContext(const ThreadContext& ctx) { +void __LoadContext(ThreadContext& ctx) { Core::g_app_core->LoadContext(ctx); } /// Resets a thread -void __ResetThread(Thread* t, s32 lowest_priority) { +void __ResetThread(Thread* t, u32 arg, s32 lowest_priority) { memset(&t->context, 0, sizeof(ThreadContext)); + t->context.cpu_registers[0] = arg; t->context.pc = t->entry_point; t->context.sp = t->stack_top; + t->context.cpsr = 0x1F; // Usermode if (t->current_priority < lowest_priority) { t->current_priority = t->initial_priority; @@ -201,7 +182,7 @@ Thread* __NextThread() { } /// Puts a thread in the wait state for the given type/reason -void __WaitCurThread(WaitType wait_type, const char* reason) { +void WaitCurThread(WaitType wait_type, const char* reason) { Thread* t = __GetCurrentThread(); t->wait_type = wait_type; __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); @@ -248,7 +229,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio } /// Creates a new thread - wrapper for external user -Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, +Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, u32 stack_top, int stack_size) { if (name == NULL) { ERROR_LOG(KERNEL, "CreateThread(): NULL name"); @@ -275,6 +256,8 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 process Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, stack_size); + __ResetThread(t, arg, 0); + HLE::EatCycles(32000); // This won't schedule to the new thread, but it may to one woken from eating cycles. @@ -299,7 +282,7 @@ Handle SetupMainThread(s32 priority, int stack_size) { Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); - __ResetThread(t, 0); + __ResetThread(t, 0, 0); // If running another thread already, set it to "ready" state Thread* cur = __GetCurrentThread(); @@ -317,18 +300,16 @@ Handle SetupMainThread(s32 priority, int stack_size) { /// Reschedules to the next available thread (call after current thread is suspended) void Reschedule(const char* reason) { + Thread* prev = __GetCurrentThread(); Thread* next = __NextThread(); if (next > 0) { __SwitchContext(next, reason); - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Put current thread in a wait state - on WaitSynchronization -void WaitThread_Synchronization() { - // TODO(bunnei): Just a placeholder function for now... FixMe - __WaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called"); + // Hack - automatically change previous thread (which would have been in "wait" state) to + // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to + // actually wait for whatever event it is supposed to be waiting on. + __ChangeReadyState(prev, true); + } } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0d1fe19bf2..82bf16082e 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -20,10 +20,31 @@ enum ThreadProcessorId { THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores }; +enum ThreadStatus { + THREADSTATUS_RUNNING = 1, + THREADSTATUS_READY = 2, + THREADSTATUS_WAIT = 4, + THREADSTATUS_SUSPEND = 8, + THREADSTATUS_DORMANT = 16, + THREADSTATUS_DEAD = 32, + THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND +}; + +enum WaitType { + WAITTYPE_NONE, + WAITTYPE_SLEEP, + WAITTYPE_SEMA, + WAITTYPE_EVENTFLAG, + WAITTYPE_THREADEND, + WAITTYPE_VBLANK, + WAITTYPE_MUTEX, + WAITTYPE_SYNCH, +}; + namespace Kernel { /// Creates a new thread - wrapper for external user -Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id, +Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Sets up the primary application thread @@ -32,6 +53,9 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) void Reschedule(const char* reason); +/// Puts a thread in the wait state for the given type/reason +void WaitCurThread(WaitType wait_type, const char* reason); + /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle); -- cgit v1.2.3 From d26f3d4c1ff27f740fe7185e1bca7dcfc5851919 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 22 May 2014 19:06:12 -0400 Subject: kernel: refactored function naming to remove "__" prefix --- src/core/hle/kernel/kernel.cpp | 15 +++++--- src/core/hle/kernel/kernel.h | 9 +++-- src/core/hle/kernel/mutex.cpp | 28 +++++++-------- src/core/hle/kernel/thread.cpp | 78 +++++++++++++++++++++--------------------- src/core/hle/kernel/thread.h | 4 +-- src/core/loader.cpp | 6 ++-- 6 files changed, 75 insertions(+), 65 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 45e36173c0..de80de8937 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -139,15 +139,20 @@ void Shutdown() { Kernel::ThreadingShutdown(); } -} // namespace - -bool __KernelLoadExec(u32 entry_point) { - Kernel::Init(); +/** + * Loads executable stored at specified address + * @entry_point Entry point in memory of loaded executable + * @return True on success, otherwise false + */ +bool LoadExec(u32 entry_point) { + Init(); Core::g_app_core->SetPC(entry_point); // 0x30 is the typical main thread priority I've seen used so far - Handle thread_id = Kernel::SetupMainThread(0x30); + Handle thread = Kernel::SetupMainThread(0x30); return true; } + +} // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1803399142..7cd79c2c41 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -144,6 +144,11 @@ private: extern ObjectPool g_object_pool; -} // namespace +/** + * Loads executable stored at specified address + * @entry_point Entry point in memory of loaded executable + * @return True on success, otherwise false + */ +bool LoadExec(u32 entry_point); -bool __KernelLoadExec(u32 entry_point); +} // namespace diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 7cf3439e98..019efbc785 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -30,17 +30,17 @@ public: typedef std::multimap MutexMap; static MutexMap g_mutex_held_locks; -void __MutexAcquireLock(Mutex* mutex, Handle thread) { +void MutexAcquireLock(Mutex* mutex, Handle thread) { g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); mutex->lock_thread = thread; } -void __MutexAcquireLock(Mutex* mutex) { - Handle thread = GetCurrentThread(); - __MutexAcquireLock(mutex, thread); +void MutexAcquireLock(Mutex* mutex) { + Handle thread = GetCurrentThreadHandle(); + MutexAcquireLock(mutex, thread); } -void __MutexEraseLock(Mutex* mutex) { +void MutexEraseLock(Mutex* mutex) { Handle handle = mutex->GetHandle(); auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { @@ -52,29 +52,29 @@ void __MutexEraseLock(Mutex* mutex) { mutex->lock_thread = -1; } -bool __LockMutex(Mutex* mutex) { +bool LockMutex(Mutex* mutex) { // Mutex alread locked? if (mutex->locked) { return false; } - __MutexAcquireLock(mutex); + MutexAcquireLock(mutex); return true; } -bool __ReleaseMutexForThread(Mutex* mutex, Handle thread) { - __MutexAcquireLock(mutex, thread); +bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { + MutexAcquireLock(mutex, thread); Kernel::ResumeThreadFromWait(thread); return true; } -bool __ReleaseMutex(Mutex* mutex) { - __MutexEraseLock(mutex); +bool ReleaseMutex(Mutex* mutex) { + MutexEraseLock(mutex); bool woke_threads = false; auto iter = mutex->waiting_threads.begin(); // Find the next waiting thread for the mutex... while (!woke_threads && !mutex->waiting_threads.empty()) { - woke_threads |= __ReleaseMutexForThread(mutex, *iter); + woke_threads |= ReleaseMutexForThread(mutex, *iter); mutex->waiting_threads.erase(iter); } // Reset mutex lock thread handle, nothing is waiting @@ -91,7 +91,7 @@ bool __ReleaseMutex(Mutex* mutex) { */ Result ReleaseMutex(Handle handle) { Mutex* mutex = Kernel::g_object_pool.GetFast(handle); - if (!__ReleaseMutex(mutex)) { + if (!ReleaseMutex(mutex)) { return -1; } return 0; @@ -110,7 +110,7 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) { // Acquire mutex with current thread if initialized as locked... if (mutex->locked) { - __MutexAcquireLock(mutex); + MutexAcquireLock(mutex); // Otherwise, reset lock thread handle } else { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 934ca87c4d..5f1d5c4002 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -64,28 +64,33 @@ Thread* g_current_thread; /// Gets the current thread -inline Thread* __GetCurrentThread() { +inline Thread* GetCurrentThread() { return g_current_thread; } +/// Gets the current thread handle +Handle GetCurrentThreadHandle() { + return GetCurrentThread()->GetHandle(); +} + /// Sets the current thread -inline void __SetCurrentThread(Thread* t) { +inline void SetCurrentThread(Thread* t) { g_current_thread = t; g_current_thread_handle = t->GetHandle(); } /// Saves the current CPU context -void __SaveContext(ThreadContext& ctx) { +void SaveContext(ThreadContext& ctx) { Core::g_app_core->SaveContext(ctx); } /// Loads a CPU context -void __LoadContext(ThreadContext& ctx) { +void LoadContext(ThreadContext& ctx) { Core::g_app_core->LoadContext(ctx); } /// Resets a thread -void __ResetThread(Thread* t, u32 arg, s32 lowest_priority) { +void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { memset(&t->context, 0, sizeof(ThreadContext)); t->context.cpu_registers[0] = arg; @@ -101,7 +106,7 @@ void __ResetThread(Thread* t, u32 arg, s32 lowest_priority) { } /// Change a thread to "ready" state -void __ChangeReadyState(Thread* t, bool ready) { +void ChangeReadyState(Thread* t, bool ready) { Handle handle = t->GetHandle(); if (t->IsReady()) { if (!ready) { @@ -118,11 +123,11 @@ void __ChangeReadyState(Thread* t, bool ready) { } /// Changes a threads state -void __ChangeThreadState(Thread* t, ThreadStatus new_status) { +void ChangeThreadState(Thread* t, ThreadStatus new_status) { if (!t || t->status == new_status) { return; } - __ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); + ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); t->status = new_status; if (new_status == THREADSTATUS_WAIT) { @@ -133,42 +138,42 @@ void __ChangeThreadState(Thread* t, ThreadStatus new_status) { } /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) -void __CallThread(Thread* t) { +void CallThread(Thread* t) { // Stop waiting if (t->wait_type != WAITTYPE_NONE) { t->wait_type = WAITTYPE_NONE; } - __ChangeThreadState(t, THREADSTATUS_READY); + ChangeThreadState(t, THREADSTATUS_READY); } /// Switches CPU context to that of the specified thread -void __SwitchContext(Thread* t, const char* reason) { - Thread* cur = __GetCurrentThread(); +void SwitchContext(Thread* t, const char* reason) { + Thread* cur = GetCurrentThread(); // Save context for current thread if (cur) { - __SaveContext(cur->context); + SaveContext(cur->context); if (cur->IsRunning()) { - __ChangeReadyState(cur, true); + ChangeReadyState(cur, true); } } // Load context of new thread if (t) { - __SetCurrentThread(t); - __ChangeReadyState(t, false); + SetCurrentThread(t); + ChangeReadyState(t, false); t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; t->wait_type = WAITTYPE_NONE; - __LoadContext(t->context); + LoadContext(t->context); } else { - __SetCurrentThread(NULL); + SetCurrentThread(NULL); } } /// Gets the next thread that is ready to be run by priority -Thread* __NextThread() { +Thread* NextThread() { Handle next; - Thread* cur = __GetCurrentThread(); + Thread* cur = GetCurrentThread(); if (cur && cur->IsRunning()) { next = g_thread_ready_queue.pop_first_better(cur->current_priority); @@ -183,9 +188,9 @@ Thread* __NextThread() { /// Puts a thread in the wait state for the given type/reason void WaitCurThread(WaitType wait_type, const char* reason) { - Thread* t = __GetCurrentThread(); + Thread* t = GetCurrentThread(); t->wait_type = wait_type; - __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); + ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); } /// Resumes a thread from waiting by marking it as "ready" @@ -195,7 +200,7 @@ void ResumeThreadFromWait(Handle handle) { if (t) { t->status &= ~THREADSTATUS_WAIT; if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { - __ChangeReadyState(t, true); + ChangeReadyState(t, true); } } } @@ -256,7 +261,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, stack_size); - __ResetThread(t, arg, 0); + ResetThread(t, arg, 0); HLE::EatCycles(32000); @@ -264,16 +269,11 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 // Technically, this should not eat all at once, and reschedule in the middle, but that's hard. HLE::ReSchedule("thread created"); - __CallThread(t); + CallThread(t); return handle; } -/// Gets the current thread -Handle GetCurrentThread() { - return __GetCurrentThread()->GetHandle(); -} - /// Sets up the primary application thread Handle SetupMainThread(s32 priority, int stack_size) { Handle handle; @@ -282,33 +282,33 @@ Handle SetupMainThread(s32 priority, int stack_size) { Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); - __ResetThread(t, 0, 0); + ResetThread(t, 0, 0); // If running another thread already, set it to "ready" state - Thread* cur = __GetCurrentThread(); + Thread* cur = GetCurrentThread(); if (cur && cur->IsRunning()) { - __ChangeReadyState(cur, true); + ChangeReadyState(cur, true); } // Run new "main" thread - __SetCurrentThread(t); + SetCurrentThread(t); t->status = THREADSTATUS_RUNNING; - __LoadContext(t->context); + LoadContext(t->context); return handle; } /// Reschedules to the next available thread (call after current thread is suspended) void Reschedule(const char* reason) { - Thread* prev = __GetCurrentThread(); - Thread* next = __NextThread(); + Thread* prev = GetCurrentThread(); + Thread* next = NextThread(); if (next > 0) { - __SwitchContext(next, reason); + SwitchContext(next, reason); // Hack - automatically change previous thread (which would have been in "wait" state) to // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to // actually wait for whatever event it is supposed to be waiting on. - __ChangeReadyState(prev, true); + ChangeReadyState(prev, true); } } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 82bf16082e..a9e9eb95fb 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -59,8 +59,8 @@ void WaitCurThread(WaitType wait_type, const char* reason); /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle); -/// Gets the current thread -Handle GetCurrentThread(); +/// Gets the current thread handle +Handle GetCurrentThreadHandle(); /// Put current thread in a wait state - on WaitSynchronization void WaitThread_Synchronization(); diff --git a/src/core/loader.cpp b/src/core/loader.cpp index 444b75feba..ff1c873bb6 100644 --- a/src/core/loader.cpp +++ b/src/core/loader.cpp @@ -56,7 +56,7 @@ bool Load_ELF(std::string &filename) { elf_reader = new ElfReader(buffer); elf_reader->LoadInto(0x00100000); - __KernelLoadExec(elf_reader->GetEntryPoint()); + Kernel::LoadExec(elf_reader->GetEntryPoint()); delete[] buffer; delete elf_reader; @@ -102,7 +102,7 @@ bool Load_DAT(std::string &filename) { *d++ = (*s++); } - __KernelLoadExec(entry_point); + Kernel::LoadExec(entry_point); delete[] buffer; @@ -144,7 +144,7 @@ bool Load_BIN(std::string &filename) { *d++ = (*s++); } - __KernelLoadExec(entry_point); + Kernel::LoadExec(entry_point); delete[] buffer; } -- cgit v1.2.3 From 7c0b0060764e75738bc9d4417d0bfd510e54ae4e Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 22 May 2014 19:32:45 -0400 Subject: thread: removed unused SwitchContext/Reschedule reason field, added missing arg parameter to SVC CreateThread --- src/core/hle/kernel/thread.cpp | 6 +++--- src/core/hle/kernel/thread.h | 2 +- src/core/hle/svc.cpp | 13 +++++-------- 3 files changed, 9 insertions(+), 12 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 5f1d5c4002..189f7d5f50 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -147,7 +147,7 @@ void CallThread(Thread* t) { } /// Switches CPU context to that of the specified thread -void SwitchContext(Thread* t, const char* reason) { +void SwitchContext(Thread* t) { Thread* cur = GetCurrentThread(); // Save context for current thread @@ -299,11 +299,11 @@ Handle SetupMainThread(s32 priority, int stack_size) { } /// Reschedules to the next available thread (call after current thread is suspended) -void Reschedule(const char* reason) { +void Reschedule() { Thread* prev = GetCurrentThread(); Thread* next = NextThread(); if (next > 0) { - SwitchContext(next, reason); + SwitchContext(next); // Hack - automatically change previous thread (which would have been in "wait" state) to // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index a9e9eb95fb..d54f47aaf7 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -51,7 +51,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) -void Reschedule(const char* reason); +void Reschedule(); /// Puts a thread in the wait state for the given type/reason void WaitCurThread(WaitType wait_type, const char* reason); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 14d512b993..b1854a36e2 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -106,10 +106,9 @@ Result CloseHandle(Handle handle) { /// Wait for a handle to synchronize, timeout after the specified nanoseconds Result WaitSynchronization1(Handle handle, s64 nano_seconds) { - // ImplementMe DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", handle, nano_seconds); - Kernel::Reschedule("WaitSynchronization1"); + Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronization1"); // TODO(bunnei): Is this correct? return 0; } @@ -117,16 +116,14 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) { Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { s32* out = (s32*)_out; Handle* handles = (Handle*)_handles; - // ImplementMe - + DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", handle_count, (wait_all ? "true" : "false"), nano_seconds); - + for (u32 i = 0; i < handle_count; i++) { DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); } - Kernel::Reschedule("WaitSynchronizationN"); - + Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronizationN"); // TODO(bunnei): Is this correct? return 0; } @@ -174,7 +171,7 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p name = buff; } - Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id, + Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, stack_top); Core::g_app_core->SetReg(1, thread); -- cgit v1.2.3 From b99ac2c3d67e2bcaa2c6eac220f1e93f4576c4fe Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 22 May 2014 19:36:56 -0400 Subject: thread: renamed "WaitCurThread" to "WaitCurrentThread", removed unused "reason" argument --- src/core/hle/kernel/thread.cpp | 4 ++-- src/core/hle/kernel/thread.h | 4 ++-- src/core/hle/svc.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 189f7d5f50..bf4c8353ce 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -186,8 +186,8 @@ Thread* NextThread() { return Kernel::g_object_pool.GetFast(next); } -/// Puts a thread in the wait state for the given type/reason -void WaitCurThread(WaitType wait_type, const char* reason) { +/// Puts the current thread in the wait state for the given type +void WaitCurrentThread(WaitType wait_type) { Thread* t = GetCurrentThread(); t->wait_type = wait_type; ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d54f47aaf7..9628f165d6 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); /// Reschedules to the next available thread (call after current thread is suspended) void Reschedule(); -/// Puts a thread in the wait state for the given type/reason -void WaitCurThread(WaitType wait_type, const char* reason); +/// Puts the current thread in the wait state for the given type +void WaitCurrentThread(WaitType wait_type); /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index b1854a36e2..8018a43a27 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -108,7 +108,7 @@ Result CloseHandle(Handle handle) { Result WaitSynchronization1(Handle handle, s64 nano_seconds) { DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", handle, nano_seconds); - Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronization1"); // TODO(bunnei): Is this correct? + Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? return 0; } @@ -123,7 +123,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa for (u32 i = 0; i < handle_count; i++) { DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); } - Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronizationN"); // TODO(bunnei): Is this correct? + Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? return 0; } -- cgit v1.2.3