kern: unify all waiting semantics to use single api

This commit is contained in:
Michael Scire 2021-09-19 10:11:56 -07:00 committed by SciresM
parent f6fb5f2c8d
commit 90732ff311
22 changed files with 904 additions and 683 deletions

View file

@ -27,59 +27,9 @@ namespace ams::kern {
KThread::WaiterList m_wait_list;
public:
constexpr ALWAYS_INLINE KLightConditionVariable() : m_wait_list() { /* ... */ }
private:
void WaitImpl(KLightLock *lock, s64 timeout, bool allow_terminating_thread) {
KThread *owner = GetCurrentThreadPointer();
KHardwareTimer *timer;
/* Sleep the thread. */
{
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep();
return;
}
lock->Unlock();
/* Set the thread as waiting. */
GetCurrentThread().SetState(KThread::ThreadState_Waiting);
/* Add the thread to the queue. */
m_wait_list.push_back(GetCurrentThread());
}
/* Remove the thread from the wait list. */
{
KScopedSchedulerLock sl;
m_wait_list.erase(m_wait_list.iterator_to(GetCurrentThread()));
}
/* Cancel the task that the sleep setup. */
if (timer != nullptr) {
timer->CancelTask(owner);
}
/* Re-acquire the lock. */
lock->Lock();
}
public:
void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true) {
this->WaitImpl(lock, timeout, allow_terminating_thread);
}
void Broadcast() {
KScopedSchedulerLock lk;
/* Signal all threads. */
for (auto &thread : m_wait_list) {
thread.SetState(KThread::ThreadState_Runnable);
}
}
void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true);
void Broadcast();
};
}

View file

@ -27,12 +27,12 @@ namespace ams::kern {
MESOSPHERE_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject);
private:
KLightSession *m_parent;
KThreadQueue m_request_queue;
KThreadQueue m_server_queue;
KThread::WaiterList m_request_list;
KThread *m_current_request;
u64 m_server_thread_id;
KThread *m_server_thread;
public:
constexpr KLightServerSession() : m_parent(), m_request_queue(), m_server_queue(), m_current_request(), m_server_thread() { /* ... */ }
constexpr KLightServerSession() : m_parent(), m_request_list(), m_current_request(), m_server_thread_id(), m_server_thread() { /* ... */ }
void Initialize(KLightSession *parent) {
/* Set member variables. */

View file

@ -45,7 +45,39 @@ namespace ams::kern {
public:
virtual void Finalize() override;
virtual bool IsSignaled() const { AMS_INFINITE_LOOP(); }
virtual void DumpWaiters();
void DumpWaiters();
ALWAYS_INLINE void LinkNode(ThreadListNode *node) {
/* Link the node to the list. */
if (m_thread_list_tail == nullptr) {
m_thread_list_head = node;
} else {
m_thread_list_tail->next = node;
}
m_thread_list_tail = node;
}
ALWAYS_INLINE void UnlinkNode(ThreadListNode *node) {
/* Unlink the node from the list. */
ThreadListNode *prev_ptr = reinterpret_cast<ThreadListNode *>(std::addressof(m_thread_list_head));
ThreadListNode *prev_val = nullptr;
ThreadListNode *prev, *tail_prev;
do {
prev = prev_ptr;
prev_ptr = prev_ptr->next;
tail_prev = prev_val;
prev_val = prev_ptr;
} while (prev_ptr != node);
if (m_thread_list_tail == node) {
m_thread_list_tail = tail_prev;
}
prev->next = node->next;
}
};
}

View file

@ -37,6 +37,7 @@ namespace ams::kern {
friend class KProcess;
friend class KConditionVariable;
friend class KAddressArbiter;
friend class KThreadQueue;
public:
static constexpr s32 MainThreadPriority = 1;
static constexpr s32 IdleThreadPriority = 64;
@ -191,7 +192,6 @@ namespace ams::kern {
KAffinityMask m_physical_affinity_mask{};
u64 m_thread_id{};
std::atomic<s64> m_cpu_time{};
KSynchronizationObject *m_synced_object{};
KProcessAddress m_address_key{};
KProcess *m_parent{};
void *m_kernel_stack_top{};
@ -204,9 +204,7 @@ namespace ams::kern {
s64 m_last_scheduled_tick{};
QueueEntry m_per_core_priority_queue_entry[cpu::NumCores]{};
KLightLock *m_waiting_lock{};
KThreadQueue *m_sleeping_queue{};
KThreadQueue *m_wait_queue{};
WaiterList m_waiter_list{};
WaiterList m_pinned_waiter_list{};
KThread *m_lock_owner{};
@ -215,6 +213,7 @@ namespace ams::kern {
u32 m_address_key_value{};
u32 m_suspend_request_flags{};
u32 m_suspend_allowed_flags{};
s32 m_synced_index{};
Result m_wait_result;
Result m_debug_exception_result;
s32 m_base_priority{};
@ -374,6 +373,8 @@ namespace ams::kern {
void FinishTermination();
void IncreaseBasePriority(s32 priority);
NOINLINE void SetState(ThreadState state);
public:
constexpr u64 GetThreadId() const { return m_thread_id; }
@ -390,7 +391,6 @@ namespace ams::kern {
constexpr ThreadState GetState() const { return static_cast<ThreadState>(m_thread_state & ThreadState_Mask); }
constexpr ThreadState GetRawState() const { return m_thread_state; }
NOINLINE void SetState(ThreadState state);
NOINLINE KThreadContext *GetContextForSchedulerLoop();
@ -442,8 +442,6 @@ namespace ams::kern {
constexpr QueueEntry &GetPriorityQueueEntry(s32 core) { return m_per_core_priority_queue_entry[core]; }
constexpr const QueueEntry &GetPriorityQueueEntry(s32 core) const { return m_per_core_priority_queue_entry[core]; }
constexpr void SetSleepingQueue(KThreadQueue *q) { m_sleeping_queue = q; }
constexpr ConditionVariableThreadTree *GetConditionVariableTree() const { return m_condvar_tree; }
constexpr s32 GetNumKernelWaiters() const { return m_num_kernel_waiters; }
@ -460,29 +458,22 @@ namespace ams::kern {
constexpr void SetLockOwner(KThread *owner) { m_lock_owner = owner; }
constexpr KThread *GetLockOwner() const { return m_lock_owner; }
constexpr void SetSyncedObject(KSynchronizationObject *obj, Result wait_res) {
MESOSPHERE_ASSERT_THIS();
constexpr void ClearWaitQueue() { m_wait_queue = nullptr; }
m_synced_object = obj;
m_wait_result = wait_res;
}
void BeginWait(KThreadQueue *queue);
void NotifyAvailable(KSynchronizationObject *signaled_object, Result wait_result);
void EndWait(Result wait_result);
void CancelWait(Result wait_result, bool cancel_timer_task);
constexpr Result GetWaitResult(KSynchronizationObject **out) const {
MESOSPHERE_ASSERT_THIS();
constexpr void SetSyncedIndex(s32 index) { m_synced_index = index; }
constexpr s32 GetSyncedIndex() const { return m_synced_index; }
*out = m_synced_object;
return m_wait_result;
}
constexpr void SetWaitResult(Result wait_res) { m_wait_result = wait_res; }
constexpr Result GetWaitResult() const { return m_wait_result; }
constexpr void SetDebugExceptionResult(Result result) {
MESOSPHERE_ASSERT_THIS();
m_debug_exception_result = result;
}
constexpr void SetDebugExceptionResult(Result result) { m_debug_exception_result = result; }
constexpr Result GetDebugExceptionResult() const {
MESOSPHERE_ASSERT_THIS();
return m_debug_exception_result;
}
constexpr Result GetDebugExceptionResult() const { return m_debug_exception_result; }
void WaitCancel();
@ -585,8 +576,6 @@ namespace ams::kern {
}
}
void Wakeup();
void SetBasePriority(s32 priority);
Result SetPriorityToIdle();

View file

@ -16,69 +16,28 @@
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_thread.hpp>
#include <mesosphere/kern_select_hardware_timer.hpp>
namespace ams::kern {
class KThreadQueue {
private:
KThread::WaiterList m_wait_list;
KHardwareTimer *m_hardware_timer;
public:
constexpr ALWAYS_INLINE KThreadQueue() : m_wait_list() { /* ... */ }
constexpr ALWAYS_INLINE KThreadQueue() : m_hardware_timer(nullptr) { /* ... */ }
bool IsEmpty() const { return m_wait_list.empty(); }
constexpr void SetHardwareTimer(KHardwareTimer *timer) { m_hardware_timer = timer; }
KThread::WaiterList::iterator begin() { return m_wait_list.begin(); }
KThread::WaiterList::iterator end() { return m_wait_list.end(); }
virtual void NotifyAvailable(KThread *waiting_thread, KSynchronizationObject *signaled_object, Result wait_result);
virtual void EndWait(KThread *waiting_thread, Result wait_result);
virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task);
};
bool SleepThread(KThread *t) {
KScopedSchedulerLock sl;
class KThreadQueueWithoutEndWait : public KThreadQueue {
public:
constexpr ALWAYS_INLINE KThreadQueueWithoutEndWait() : KThreadQueue() { /* ... */ }
/* If the thread needs terminating, don't enqueue it. */
if (t->IsTerminationRequested()) {
return false;
}
/* Set the thread's queue and mark it as waiting. */
t->SetSleepingQueue(this);
t->SetState(KThread::ThreadState_Waiting);
/* Add the thread to the queue. */
m_wait_list.push_back(*t);
return true;
}
void WakeupThread(KThread *t) {
KScopedSchedulerLock sl;
/* Remove the thread from the queue. */
m_wait_list.erase(m_wait_list.iterator_to(*t));
/* Mark the thread as no longer sleeping. */
t->SetState(KThread::ThreadState_Runnable);
t->SetSleepingQueue(nullptr);
}
KThread *WakeupFrontThread() {
KScopedSchedulerLock sl;
if (m_wait_list.empty()) {
return nullptr;
} else {
/* Remove the thread from the queue. */
auto it = m_wait_list.begin();
KThread *thread = std::addressof(*it);
m_wait_list.erase(it);
MESOSPHERE_ASSERT(thread->GetState() == KThread::ThreadState_Waiting);
/* Mark the thread as no longer sleeping. */
thread->SetState(KThread::ThreadState_Runnable);
thread->SetSleepingQueue(nullptr);
return thread;
}
}
virtual void EndWait(KThread *waiting_thread, Result wait_result) override final;
};
}

View file

@ -20,14 +20,13 @@
namespace ams::kern {
class KWaitObject : public KTimerTask {
class KWaitObject {
private:
KThread::WaiterList m_wait_list;
bool m_timer_used;
KThread *m_next_thread;
public:
constexpr KWaitObject() : m_wait_list(), m_timer_used() { /* ... */ }
constexpr KWaitObject() : m_wait_list(), m_next_thread() { /* ... */ }
virtual void OnTimer() override;
Result Synchronize(s64 timeout);
};

View file

@ -32,8 +32,7 @@ namespace ams::kern {
private:
KWorkerTask *m_head_task;
KWorkerTask *m_tail_task;
KThread *m_thread;
bool m_active;
KThread *m_waiting_thread;
private:
static void ThreadFunction(uintptr_t arg);
void ThreadFunctionImpl();
@ -41,7 +40,7 @@ namespace ams::kern {
KWorkerTask *GetTask();
void AddTask(KWorkerTask *task);
public:
constexpr KWorkerTaskManager() : m_head_task(), m_tail_task(), m_thread(), m_active() { /* ... */ }
constexpr KWorkerTaskManager() : m_head_task(), m_tail_task(), m_waiting_thread() { /* ... */ }
NOINLINE void Initialize(s32 priority);
static void AddTask(WorkerType type, KWorkerTask *task);