void Thread::Stop() { // Release all the mutexes that this thread holds ReleaseThreadMutexes(this); // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); wakeup_callback_handle_table.Close(callback_handle); callback_handle = 0; // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) if (status == THREADSTATUS_READY){ ready_queue.remove(current_priority, this); } status = THREADSTATUS_DEAD; WakeupAllWaitingThreads(); // Clean up any dangling references in objects that this thread was waiting for for (auto& wait_object : wait_objects) { wait_object->RemoveWaitingThread(this); } wait_objects.clear(); // Mark the TLS slot in the thread's page as free. u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); HLE::Reschedule(__func__); }
/** * Switches the CPU's active thread context to that of the specified thread * @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 if (previous_thread) { Core::g_app_core->SaveContext(previous_thread->context); if (previous_thread->status == THREADSTATUS_RUNNING) { // This is only the case when a reschedule is triggered without the current thread // yielding execution (i.e. an event triggered, system core time-sliced, etc) ready_queue.push_front(previous_thread->current_priority, previous_thread); previous_thread->status = THREADSTATUS_READY; } } // Load context of new thread if (new_thread) { current_thread = new_thread; ready_queue.remove(new_thread->current_priority, new_thread); new_thread->status = THREADSTATUS_RUNNING; Core::g_app_core->LoadContext(new_thread->context); } else { current_thread = nullptr; } }
/// Set the priority of the thread specified by handle Result SetThreadPriority(Handle handle, s32 priority) { Thread* thread = nullptr; if (!handle) { thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? } else { thread = g_object_pool.GetFast<Thread>(handle); } _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); // If priority is invalid, clamp to valid range if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority); // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm // validity of this priority = new_priority; } // Change thread priority s32 old = thread->current_priority; g_thread_ready_queue.remove(old, handle); thread->current_priority = priority; g_thread_ready_queue.prepare(thread->current_priority); // Change thread status to "ready" and push to ready queue if (thread->IsRunning()) { thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; } if (thread->IsReady()) { g_thread_ready_queue.push_back(thread->current_priority, handle); } return 0; }
/// Change a thread to "ready" state void ChangeReadyState(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(t->current_priority, handle); } t->status = THREADSTATUS_READY; } }
void Thread::SetPriority(s32 priority) { ClampPriority(this, &priority); if (current_priority == priority) { return; } if (status == THREADSTATUS_READY) { // If thread was ready, adjust queues ready_queue.remove(current_priority, this); ready_queue.prepare(priority); ready_queue.push_back(priority, this); } current_priority = priority; }
void Thread::Stop() { // Release all the mutexes that this thread holds ReleaseThreadMutexes(this); // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) if (status == THREADSTATUS_READY){ ready_queue.remove(current_priority, this); } status = THREADSTATUS_DEAD; WakeupAllWaitingThreads(); // Clean up any dangling references in objects that this thread was waiting for for (auto& wait_object : wait_objects) { wait_object->RemoveWaitingThread(this); } }