|
|
|
@ -44,7 +44,7 @@ Thread::~Thread() = default; |
|
|
|
void Thread::Stop() { |
|
|
|
{ |
|
|
|
KScopedSchedulerLock lock(kernel); |
|
|
|
SetState(ThreadStatus::Dead); |
|
|
|
SetState(ThreadState::Terminated); |
|
|
|
signaled = true; |
|
|
|
NotifyAvailable(); |
|
|
|
kernel.GlobalHandleTable().Close(global_handle); |
|
|
|
@ -62,54 +62,43 @@ void Thread::Stop() { |
|
|
|
|
|
|
|
void Thread::Wakeup() { |
|
|
|
KScopedSchedulerLock lock(kernel); |
|
|
|
switch (status) { |
|
|
|
case ThreadStatus::Paused: |
|
|
|
case ThreadStatus::WaitSynch: |
|
|
|
case ThreadStatus::WaitHLEEvent: |
|
|
|
case ThreadStatus::WaitSleep: |
|
|
|
case ThreadStatus::WaitIPC: |
|
|
|
case ThreadStatus::WaitMutex: |
|
|
|
case ThreadStatus::WaitCondVar: |
|
|
|
case ThreadStatus::WaitArb: |
|
|
|
case ThreadStatus::Dormant: |
|
|
|
break; |
|
|
|
|
|
|
|
case ThreadStatus::Ready: |
|
|
|
switch (thread_state) { |
|
|
|
case ThreadState::Runnable: |
|
|
|
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
|
|
|
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
|
|
|
// already been set to ThreadStatus::Ready.
|
|
|
|
return; |
|
|
|
case ThreadStatus::Dead: |
|
|
|
case ThreadState::Terminated: |
|
|
|
// This should never happen, as threads must complete before being stopped.
|
|
|
|
DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", |
|
|
|
GetObjectId()); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
SetState(ThreadStatus::Ready); |
|
|
|
SetState(ThreadState::Runnable); |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::OnWakeUp() { |
|
|
|
KScopedSchedulerLock lock(kernel); |
|
|
|
SetState(ThreadStatus::Ready); |
|
|
|
SetState(ThreadState::Runnable); |
|
|
|
} |
|
|
|
|
|
|
|
ResultCode Thread::Start() { |
|
|
|
KScopedSchedulerLock lock(kernel); |
|
|
|
SetState(ThreadStatus::Ready); |
|
|
|
SetState(ThreadState::Runnable); |
|
|
|
return RESULT_SUCCESS; |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::CancelWait() { |
|
|
|
KScopedSchedulerLock lock(kernel); |
|
|
|
if (GetState() != ThreadSchedStatus::Paused || !is_cancellable) { |
|
|
|
if (GetState() != ThreadState::Waiting || !is_cancellable) { |
|
|
|
is_sync_cancelled = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
// TODO(Blinkhawk): Implement cancel of server session
|
|
|
|
is_sync_cancelled = false; |
|
|
|
SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); |
|
|
|
SetState(ThreadStatus::Ready); |
|
|
|
SetState(ThreadState::Runnable); |
|
|
|
} |
|
|
|
|
|
|
|
static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, |
|
|
|
@ -173,7 +162,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy |
|
|
|
std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel); |
|
|
|
|
|
|
|
thread->thread_id = kernel.CreateNewThreadID(); |
|
|
|
thread->status = ThreadStatus::Dormant; |
|
|
|
thread->thread_state = ThreadState::Initialized; |
|
|
|
thread->entry_point = entry_point; |
|
|
|
thread->stack_top = stack_top; |
|
|
|
thread->disable_count = 1; |
|
|
|
@ -235,27 +224,18 @@ VAddr Thread::GetCommandBufferAddress() const { |
|
|
|
return GetTLSAddress() + command_header_offset; |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::SetState(ThreadStatus new_status) { |
|
|
|
if (new_status == status) { |
|
|
|
void Thread::SetState(ThreadState new_status) { |
|
|
|
if (new_status == thread_state) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
switch (new_status) { |
|
|
|
case ThreadStatus::Ready: |
|
|
|
SetSchedulingStatus(ThreadSchedStatus::Runnable); |
|
|
|
break; |
|
|
|
case ThreadStatus::Dormant: |
|
|
|
SetSchedulingStatus(ThreadSchedStatus::None); |
|
|
|
break; |
|
|
|
case ThreadStatus::Dead: |
|
|
|
SetSchedulingStatus(ThreadSchedStatus::Exited); |
|
|
|
break; |
|
|
|
default: |
|
|
|
SetSchedulingStatus(ThreadSchedStatus::Paused); |
|
|
|
break; |
|
|
|
if (new_status != ThreadState::Waiting) { |
|
|
|
SetWaitingCondVar(false); |
|
|
|
} |
|
|
|
|
|
|
|
status = new_status; |
|
|
|
SetSchedulingStatus(new_status); |
|
|
|
|
|
|
|
thread_state = new_status; |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::AddMutexWaiter(std::shared_ptr<Thread> thread) { |
|
|
|
@ -312,13 +292,13 @@ void Thread::UpdatePriority() { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (GetStatus() == ThreadStatus::WaitCondVar) { |
|
|
|
if (GetState() == ThreadState::Waiting && is_waiting_on_condvar) { |
|
|
|
owner_process->RemoveConditionVariableThread(SharedFrom(this)); |
|
|
|
} |
|
|
|
|
|
|
|
SetCurrentPriority(new_priority); |
|
|
|
|
|
|
|
if (GetStatus() == ThreadStatus::WaitCondVar) { |
|
|
|
if (GetState() == ThreadState::Waiting && is_waiting_on_condvar) { |
|
|
|
owner_process->InsertConditionVariableThread(SharedFrom(this)); |
|
|
|
} |
|
|
|
|
|
|
|
@ -340,7 +320,7 @@ ResultCode Thread::SetActivity(ThreadActivity value) { |
|
|
|
|
|
|
|
auto sched_status = GetState(); |
|
|
|
|
|
|
|
if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { |
|
|
|
if (sched_status != ThreadState::Runnable && sched_status != ThreadState::Waiting) { |
|
|
|
return ERR_INVALID_STATE; |
|
|
|
} |
|
|
|
|
|
|
|
@ -366,7 +346,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { |
|
|
|
Handle event_handle{}; |
|
|
|
{ |
|
|
|
KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); |
|
|
|
SetState(ThreadStatus::WaitSleep); |
|
|
|
SetState(ThreadState::Waiting); |
|
|
|
} |
|
|
|
|
|
|
|
if (event_handle != InvalidHandle) { |
|
|
|
@ -377,25 +357,24 @@ ResultCode Thread::Sleep(s64 nanoseconds) { |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { |
|
|
|
const u32 old_state = scheduling_state; |
|
|
|
const auto old_state = GetRawState(); |
|
|
|
pausing_state |= static_cast<u32>(flag); |
|
|
|
const u32 base_scheduling = static_cast<u32>(GetState()); |
|
|
|
scheduling_state = base_scheduling | pausing_state; |
|
|
|
const auto base_scheduling = GetState(); |
|
|
|
thread_state = base_scheduling | static_cast<ThreadState>(pausing_state); |
|
|
|
KScheduler::OnThreadStateChanged(kernel, this, old_state); |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { |
|
|
|
const u32 old_state = scheduling_state; |
|
|
|
const auto old_state = GetRawState(); |
|
|
|
pausing_state &= ~static_cast<u32>(flag); |
|
|
|
const u32 base_scheduling = static_cast<u32>(GetState()); |
|
|
|
scheduling_state = base_scheduling | pausing_state; |
|
|
|
const auto base_scheduling = GetState(); |
|
|
|
thread_state = base_scheduling | static_cast<ThreadState>(pausing_state); |
|
|
|
KScheduler::OnThreadStateChanged(kernel, this, old_state); |
|
|
|
} |
|
|
|
|
|
|
|
void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { |
|
|
|
const u32 old_state = scheduling_state; |
|
|
|
scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) | |
|
|
|
static_cast<u32>(new_status); |
|
|
|
void Thread::SetSchedulingStatus(ThreadState new_status) { |
|
|
|
const auto old_state = GetRawState(); |
|
|
|
thread_state = (thread_state & ThreadState::HighMask) | new_status; |
|
|
|
KScheduler::OnThreadStateChanged(kernel, this, old_state); |
|
|
|
} |
|
|
|
|
|
|
|
|