diff options
Diffstat (limited to 'src/core/hle')
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/kernel/process.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/process.h | 8 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.cpp | 71 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.h | 21 | ||||
-rw-r--r-- | src/core/hle/svc.cpp | 33 |
6 files changed, 86 insertions, 55 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index a3715e55..b5c98b24 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -115,8 +115,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { - LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess); - return nullptr; + return g_current_process; } if (!IsValid(handle)) { @@ -139,6 +138,9 @@ void Init() { Kernel::TimersInit(); Object::next_object_id = 0; + // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are + // reserved for low-level services + Process::next_process_id = 10; } /// Shutdown the kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index efae4a17..1e439db9 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -12,6 +12,8 @@ namespace Kernel { +u32 Process::next_process_id; + SharedPtr<Process> Process::Create(std::string name, u64 program_id) { SharedPtr<Process> process(new Process); diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 88ed9a5a..90881054 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -55,6 +55,8 @@ public: static const HandleType HANDLE_TYPE = HandleType::Process; HandleType GetHandleType() const override { return HANDLE_TYPE; } + static u32 next_process_id; + /// Name of the process std::string name; /// Title ID corresponding to the process @@ -69,6 +71,12 @@ public: boost::container::static_vector<AddressMapping, 8> address_mappings; ProcessFlags flags; + /// The id of this process + u32 process_id = next_process_id++; + + /// Bitmask of the used TLS slots + std::bitset<300> used_tls_slots; + /** * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them * to this process. diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 957cbdfe..afaf0cd5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -17,6 +17,7 @@ #include "core/core_timing.h" #include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/mutex.h" #include "core/hle/result.h" @@ -106,6 +107,8 @@ void Thread::Stop() { for (auto& wait_object : wait_objects) { wait_object->RemoveWaitingThread(this); } + + Kernel::g_current_process->used_tls_slots[tls_index] = false; } Thread* ArbitrateHighestPriorityThread(u32 address) { @@ -157,7 +160,7 @@ static void PriorityBoostStarvedThreads() { u64 delta = current_ticks - thread->last_running_ticks; - if (thread->status == THREADSTATUS_READY && delta > boost_timeout && !thread->idle) { + if (thread->status == THREADSTATUS_READY && delta > boost_timeout) { const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0); thread->BoostPriority(priority); } @@ -169,8 +172,6 @@ static void PriorityBoostStarvedThreads() { * @param new_thread The thread to switch to */ static void SwitchContext(Thread* new_thread) { - DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); - Thread* previous_thread = GetCurrentThread(); // Save context for previous thread @@ -188,6 +189,8 @@ static void SwitchContext(Thread* new_thread) { // Load context of new thread if (new_thread) { + DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); + current_thread = new_thread; ready_queue.remove(new_thread->current_priority, new_thread); @@ -215,6 +218,10 @@ static Thread* PopNextReadyThread() { // We have to do better than the current thread. // This call returns null when that's not possible. next = ready_queue.pop_first_better(thread->current_priority); + if (!next) { + // Otherwise just keep going with the current thread + next = thread; + } } else { next = ready_queue.pop_first(); } @@ -402,12 +409,20 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->wait_address = 0; thread->name = std::move(name); thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); + thread->owner_process = g_current_process; + thread->tls_index = -1; + + // Find the next available TLS index, and mark it as used + auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; + for (unsigned int i = 0; i < used_tls_slots.size(); ++i) { + if (used_tls_slots[i] == false) { + thread->tls_index = i; + used_tls_slots[i] = true; + break; + } + } - VAddr tls_address = Memory::TLS_AREA_VADDR + (thread->thread_id - 1) * 0x200; - - ASSERT_MSG(tls_address < Memory::TLS_AREA_VADDR_END, "Too many threads"); - - thread->tls_address = tls_address; + ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context @@ -439,6 +454,8 @@ void Thread::SetPriority(s32 priority) { // If thread was ready, adjust queues if (status == THREADSTATUS_READY) ready_queue.move(this, current_priority, priority); + else + ready_queue.prepare(priority); nominal_priority = current_priority = priority; } @@ -448,16 +465,6 @@ void Thread::BoostPriority(s32 priority) { current_priority = priority; } -SharedPtr<Thread> SetupIdleThread() { - // We need to pass a few valid values to get around parameter checking in Thread::Create. - // TODO(yuriks): Figure out a way to avoid passing the bogus VAddr parameter - auto thread = Thread::Create("idle", Memory::TLS_AREA_VADDR, THREADPRIO_LOWEST, 0, - THREADPROCESSORID_0, 0).MoveFrom(); - - thread->idle = true; - return thread; -} - SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { DEBUG_ASSERT(!GetCurrentThread()); @@ -474,24 +481,25 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { } void Reschedule() { - Thread* prev = GetCurrentThread(); - PriorityBoostStarvedThreads(); + Thread* cur = GetCurrentThread(); Thread* next = PopNextReadyThread(); HLE::g_reschedule = false; - if (next != nullptr) { - LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId()); - SwitchContext(next); - } else { - LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId()); + // Don't bother switching to the same thread + if (next == cur) + return; - for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(), - thread->current_priority, thread->status); - } + if (cur && next) { + LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); + } else if (cur) { + LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); + } else { + LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); } + + SwitchContext(next); } void Thread::SetWaitSynchronizationResult(ResultCode result) { @@ -503,7 +511,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { } VAddr Thread::GetTLSAddress() const { - return tls_address; + return Memory::TLS_AREA_VADDR + tls_index * 0x200; } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -516,9 +524,6 @@ void ThreadingInit() { thread_list.clear(); ready_queue.clear(); - - // Setup the idle thread - SetupIdleThread(); } void ThreadingShutdown() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index afdaf851..6b329c12 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -45,6 +45,7 @@ enum ThreadStatus { namespace Kernel { class Mutex; +class Process; class Thread final : public WaitObject { public: @@ -72,12 +73,6 @@ public: void Acquire() override; /** - * Checks if the thread is an idle (stub) thread - * @return True if the thread is an idle (stub) thread, false otherwise - */ - inline bool IsIdle() const { return idle; } - - /** * Gets the thread's current priority * @return The current thread's priority */ @@ -156,11 +151,12 @@ public: s32 processor_id; - VAddr tls_address; ///< Address of the Thread Local Storage of the thread + s32 tls_index; ///< Index of the Thread Local Storage of the thread /// Mutexes currently held by this thread, which will be released when it exits. boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; + SharedPtr<Process> owner_process; ///< Process that owns this thread std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address bool wait_all; ///< True if the thread is waiting on all objects before resuming @@ -168,9 +164,6 @@ public: std::string name; - /// Whether this thread is intended to never actually be executed, i.e. always idle - bool idle = false; - private: Thread(); ~Thread() override; @@ -229,14 +222,6 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); /** - * Sets up the idle thread, this is a thread that is intended to never execute instructions, - * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue - * and will try to yield on every call. - * @return The handle of the idle thread - */ -SharedPtr<Thread> SetupIdleThread(); - -/** * Initialize threading */ void ThreadingInit(); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 1ec6599c..e8159fbd 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" @@ -424,6 +425,34 @@ static ResultCode ReleaseMutex(Handle handle) { return RESULT_SUCCESS; } +/// Get the ID of the specified process +static ResultCode GetProcessId(u32* process_id, Handle process_handle) { + LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); + + const SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle); + if (process == nullptr) + return ERR_INVALID_HANDLE; + + *process_id = process->process_id; + return RESULT_SUCCESS; +} + +/// Get the ID of the process that owns the specified thread +static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { + LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); + + const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle); + if (thread == nullptr) + return ERR_INVALID_HANDLE; + + const SharedPtr<Kernel::Process> process = thread->owner_process; + + ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); + + *process_id = process->process_id; + return RESULT_SUCCESS; +} + /// Get the ID for the specified thread. static ResultCode GetThreadId(u32* thread_id, Handle handle) { LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); @@ -674,8 +703,8 @@ static const FunctionDef SVC_Table[] = { {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, {0x33, nullptr, "OpenProcess"}, {0x34, nullptr, "OpenThread"}, - {0x35, nullptr, "GetProcessId"}, - {0x36, nullptr, "GetProcessIdOfThread"}, + {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"}, + {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, {0x39, nullptr, "GetResourceLimitLimitValues"}, |