/// 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; }
void Thread::ResumeFromWait() { // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); switch (status) { case THREADSTATUS_WAIT_SYNCH: // Remove this thread from all other WaitObjects for (auto wait_object : wait_objects) wait_object->RemoveWaitingThread(this); break; case THREADSTATUS_WAIT_ARB: case THREADSTATUS_WAIT_SLEEP: break; case THREADSTATUS_RUNNING: case THREADSTATUS_READY: DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); return; case THREADSTATUS_DEAD: // This should never happen, as threads must complete before being stopped. DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.", GetObjectId()); return; } ready_queue.push_back(current_priority, this); status = THREADSTATUS_READY; }
/// 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; }
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, u32 arg, s32 processor_id, VAddr stack_top) { if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", name.c_str(), 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)) { LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); // TODO: Verify error return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } SharedPtr<Thread> thread(new Thread); thread_list.push_back(thread); ready_queue.prepare(priority); thread->thread_id = NewThreadId(); thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; thread->stack_top = stack_top; thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; thread->wait_set_output = false; thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg); ready_queue.push_back(thread->current_priority, thread.get()); thread->status = THREADSTATUS_READY; return MakeResult<SharedPtr<Thread>>(std::move(thread)); }