mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-17 00:24:23 -04:00
kern: cleanup KThread, optimize/normalize KThreadQueue/KWaitObject
This commit is contained in:
parent
1852fe8612
commit
8b2ed36698
10 changed files with 58 additions and 168 deletions
|
@ -24,7 +24,6 @@ namespace ams::kern {
|
|||
struct InfoCreateThread {
|
||||
u32 thread_id;
|
||||
uintptr_t tls_address;
|
||||
uintptr_t entrypoint;
|
||||
};
|
||||
|
||||
struct InfoExitProcess {
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace ams::kern {
|
|||
|
||||
using KThreadFunction = void (*)(uintptr_t);
|
||||
|
||||
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, public KTimerTask, public KWorkerTask {
|
||||
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, public util::IntrusiveListBaseNode<KThread>, public KTimerTask, public KWorkerTask {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
|
||||
private:
|
||||
friend class KProcess;
|
||||
|
@ -111,6 +111,8 @@ namespace ams::kern {
|
|||
constexpr void SetPrev(KThread *t) { this->prev = t; }
|
||||
constexpr void SetNext(KThread *t) { this->next = t; }
|
||||
};
|
||||
|
||||
using WaiterList = util::IntrusiveListBaseTraits<KThread>::ListType;
|
||||
private:
|
||||
static constexpr size_t PriorityInheritanceCountMax = 10;
|
||||
union SyncObjectBuffer {
|
||||
|
@ -141,13 +143,19 @@ namespace ams::kern {
|
|||
static inline std::atomic<u64> s_next_thread_id = 0;
|
||||
private:
|
||||
alignas(16) KThreadContext thread_context{};
|
||||
util::IntrusiveListNode process_list_node{};
|
||||
util::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
|
||||
s32 priority{};
|
||||
|
||||
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::condvar_arbiter_tree_node>;
|
||||
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
|
||||
|
||||
ConditionVariableThreadTree *condvar_tree{};
|
||||
uintptr_t condvar_key{};
|
||||
KAffinityMask affinity_mask{};
|
||||
u64 thread_id{};
|
||||
std::atomic<s64> cpu_time{};
|
||||
KSynchronizationObject *synced_object{};
|
||||
KLightLock *waiting_lock{};
|
||||
uintptr_t condvar_key{};
|
||||
uintptr_t entrypoint{};
|
||||
KProcessAddress address_key{};
|
||||
KProcess *parent{};
|
||||
void *kernel_stack_top{};
|
||||
|
@ -159,43 +167,31 @@ namespace ams::kern {
|
|||
s64 schedule_count{};
|
||||
s64 last_scheduled_tick{};
|
||||
QueueEntry per_core_priority_queue_entry[cpu::NumCores]{};
|
||||
QueueEntry sleeping_queue_entry{};
|
||||
KLightLock *waiting_lock{};
|
||||
|
||||
KThreadQueue *sleeping_queue{};
|
||||
util::IntrusiveListNode waiter_list_node{};
|
||||
util::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
|
||||
util::IntrusiveListNode process_list_node{};
|
||||
|
||||
using WaiterListTraits = util::IntrusiveListMemberTraitsDeferredAssert<&KThread::waiter_list_node>;
|
||||
using WaiterList = WaiterListTraits::ListType;
|
||||
|
||||
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::condvar_arbiter_tree_node>;
|
||||
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
|
||||
|
||||
WaiterList waiter_list{};
|
||||
WaiterList pinned_waiter_list{};
|
||||
KThread *lock_owner{};
|
||||
ConditionVariableThreadTree *condvar_tree{};
|
||||
uintptr_t debug_params[3]{};
|
||||
u32 address_key_value{};
|
||||
u32 suspend_request_flags{};
|
||||
u32 suspend_allowed_flags{};
|
||||
Result wait_result;
|
||||
Result debug_exception_result;
|
||||
s32 priority{};
|
||||
s32 current_core_id{};
|
||||
s32 core_id{};
|
||||
s32 base_priority{};
|
||||
s32 ideal_core_id{};
|
||||
s32 num_kernel_waiters{};
|
||||
s32 current_core_id{};
|
||||
s32 core_id{};
|
||||
KAffinityMask original_affinity_mask{};
|
||||
s32 original_ideal_core_id{};
|
||||
s32 num_core_migration_disables{};
|
||||
ThreadState thread_state{};
|
||||
std::atomic<bool> termination_requested{};
|
||||
bool ipc_cancelled{};
|
||||
bool wait_cancelled{};
|
||||
bool cancellable{};
|
||||
bool registered{};
|
||||
bool signaled{};
|
||||
bool initialized{};
|
||||
bool debug_attached{};
|
||||
|
@ -393,8 +389,6 @@ namespace ams::kern {
|
|||
constexpr QueueEntry &GetPriorityQueueEntry(s32 core) { return this->per_core_priority_queue_entry[core]; }
|
||||
constexpr const QueueEntry &GetPriorityQueueEntry(s32 core) const { return this->per_core_priority_queue_entry[core]; }
|
||||
|
||||
constexpr QueueEntry &GetSleepingQueueEntry() { return this->sleeping_queue_entry; }
|
||||
constexpr const QueueEntry &GetSleepingQueueEntry() const { return this->sleeping_queue_entry; }
|
||||
constexpr void SetSleepingQueue(KThreadQueue *q) { this->sleeping_queue = q; }
|
||||
|
||||
constexpr ConditionVariableThreadTree *GetConditionVariableTree() const { return this->condvar_tree; }
|
||||
|
@ -459,8 +453,6 @@ namespace ams::kern {
|
|||
constexpr KProcess *GetOwnerProcess() const { return this->parent; }
|
||||
constexpr bool IsUserThread() const { return this->parent != nullptr; }
|
||||
|
||||
constexpr uintptr_t GetEntrypoint() const { return this->entrypoint; }
|
||||
|
||||
constexpr KProcessAddress GetThreadLocalRegionAddress() const { return this->tls_address; }
|
||||
constexpr void *GetThreadLocalRegionHeapAddress() const { return this->tls_heap_address; }
|
||||
|
||||
|
@ -541,10 +533,6 @@ namespace ams::kern {
|
|||
virtual void OnTimer() override;
|
||||
virtual void DoWorkerTask() override;
|
||||
public:
|
||||
static constexpr bool IsWaiterListValid() {
|
||||
return WaiterListTraits::IsValid();
|
||||
}
|
||||
|
||||
static constexpr bool IsConditionVariableThreadTreeValid() {
|
||||
return ConditionVariableThreadTreeTraits::IsValid();
|
||||
}
|
||||
|
@ -555,7 +543,6 @@ namespace ams::kern {
|
|||
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
|
||||
};
|
||||
static_assert(alignof(KThread) == 0x10);
|
||||
static_assert(KThread::IsWaiterListValid());
|
||||
static_assert(KThread::IsConditionVariableThreadTreeValid());
|
||||
|
||||
class KScopedDisableDispatch {
|
||||
|
|
|
@ -21,92 +21,38 @@ namespace ams::kern {
|
|||
|
||||
class KThreadQueue {
|
||||
private:
|
||||
using Entry = KThread::QueueEntry;
|
||||
private:
|
||||
Entry root;
|
||||
KThread::WaiterList wait_list;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE KThreadQueue() : root() { /* ... */ }
|
||||
constexpr ALWAYS_INLINE KThreadQueue() : wait_list() { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsEmpty() const { return this->root.GetNext() == nullptr; }
|
||||
bool IsEmpty() const { return this->wait_list.empty(); }
|
||||
|
||||
constexpr ALWAYS_INLINE KThread *GetFront() const { return this->root.GetNext(); }
|
||||
constexpr ALWAYS_INLINE KThread *GetNext(KThread *t) const { return t->GetSleepingQueueEntry().GetNext(); }
|
||||
private:
|
||||
constexpr ALWAYS_INLINE KThread *GetBack() const { return this->root.GetPrev(); }
|
||||
|
||||
constexpr ALWAYS_INLINE void Enqueue(KThread *add) {
|
||||
/* Get the entry associated with the added thread. */
|
||||
Entry &add_entry = add->GetSleepingQueueEntry();
|
||||
|
||||
/* Get the entry associated with the end of the queue. */
|
||||
KThread *tail = this->GetBack();
|
||||
Entry &tail_entry = (tail != nullptr) ? tail->GetSleepingQueueEntry() : this->root;
|
||||
|
||||
/* Link the entries. */
|
||||
add_entry.SetPrev(tail);
|
||||
add_entry.SetNext(nullptr);
|
||||
tail_entry.SetNext(add);
|
||||
this->root.SetPrev(add);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void Remove(KThread *remove) {
|
||||
/* Get the entry associated with the thread. */
|
||||
Entry &remove_entry = remove->GetSleepingQueueEntry();
|
||||
|
||||
/* Get the entries associated with next and prev. */
|
||||
KThread *prev = remove_entry.GetPrev();
|
||||
KThread *next = remove_entry.GetNext();
|
||||
Entry &prev_entry = (prev != nullptr) ? prev->GetSleepingQueueEntry() : this->root;
|
||||
Entry &next_entry = (next != nullptr) ? next->GetSleepingQueueEntry() : this->root;
|
||||
|
||||
/* Unlink. */
|
||||
prev_entry.SetNext(next);
|
||||
next_entry.SetPrev(prev);
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE void Dequeue() {
|
||||
/* Get the front of the queue. */
|
||||
KThread *head = this->GetFront();
|
||||
if (head == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
MESOSPHERE_ASSERT(head->GetState() == KThread::ThreadState_Waiting);
|
||||
|
||||
/* Get the entry for the next head. */
|
||||
KThread *next = GetNext(head);
|
||||
Entry &next_entry = (next != nullptr) ? next->GetSleepingQueueEntry() : this->root;
|
||||
|
||||
/* Link the entries. */
|
||||
this->root.SetNext(next);
|
||||
next_entry.SetPrev(nullptr);
|
||||
|
||||
/* Clear the head's queue. */
|
||||
head->SetSleepingQueue(nullptr);
|
||||
}
|
||||
KThread::WaiterList::iterator begin() { return this->wait_list.begin(); }
|
||||
KThread::WaiterList::iterator end() { return this->wait_list.end(); }
|
||||
|
||||
bool SleepThread(KThread *t) {
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* 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. */
|
||||
this->Enqueue(t);
|
||||
|
||||
/* If the thread needs terminating, undo our work. */
|
||||
if (t->IsTerminationRequested()) {
|
||||
this->WakeupThread(t);
|
||||
return false;
|
||||
}
|
||||
this->wait_list.push_back(*t);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WakeupThread(KThread *t) {
|
||||
MESOSPHERE_ASSERT(t->GetState() == KThread::ThreadState_Waiting);
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Remove the thread from the queue. */
|
||||
this->Remove(t);
|
||||
this->wait_list.erase(this->wait_list.iterator_to(*t));
|
||||
|
||||
/* Mark the thread as no longer sleeping. */
|
||||
t->SetState(KThread::ThreadState_Runnable);
|
||||
|
@ -114,18 +60,24 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
KThread *WakeupFrontThread() {
|
||||
KThread *front = this->GetFront();
|
||||
if (front != nullptr) {
|
||||
MESOSPHERE_ASSERT(front->GetState() == KThread::ThreadState_Waiting);
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
if (this->wait_list.empty()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
/* Remove the thread from the queue. */
|
||||
this->Dequeue();
|
||||
auto it = this->wait_list.begin();
|
||||
KThread *thread = std::addressof(*it);
|
||||
this->wait_list.erase(it);
|
||||
|
||||
MESOSPHERE_ASSERT(thread->GetState() == KThread::ThreadState_Waiting);
|
||||
|
||||
/* Mark the thread as no longer sleeping. */
|
||||
front->SetState(KThread::ThreadState_Runnable);
|
||||
front->SetSleepingQueue(nullptr);
|
||||
thread->SetState(KThread::ThreadState_Runnable);
|
||||
thread->SetSleepingQueue(nullptr);
|
||||
|
||||
return thread;
|
||||
}
|
||||
return front;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -22,45 +22,13 @@ namespace ams::kern {
|
|||
|
||||
class KWaitObject : public KTimerTask {
|
||||
private:
|
||||
using Entry = KThread::QueueEntry;
|
||||
private:
|
||||
Entry root;
|
||||
KThread::WaiterList wait_list;
|
||||
bool timer_used;
|
||||
public:
|
||||
constexpr KWaitObject() : root(), timer_used() { /* ... */ }
|
||||
constexpr KWaitObject() : wait_list(), timer_used() { /* ... */ }
|
||||
|
||||
virtual void OnTimer() override;
|
||||
Result Synchronize(s64 timeout);
|
||||
private:
|
||||
constexpr ALWAYS_INLINE void Enqueue(KThread *add) {
|
||||
/* Get the entry associated with the added thread. */
|
||||
Entry &add_entry = add->GetSleepingQueueEntry();
|
||||
|
||||
/* Get the entry associated with the end of the queue. */
|
||||
KThread *tail = this->root.GetPrev();
|
||||
Entry &tail_entry = (tail != nullptr) ? tail->GetSleepingQueueEntry() : this->root;
|
||||
|
||||
/* Link the entries. */
|
||||
add_entry.SetPrev(tail);
|
||||
add_entry.SetNext(nullptr);
|
||||
tail_entry.SetNext(add);
|
||||
this->root.SetPrev(add);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE void Remove(KThread *remove) {
|
||||
/* Get the entry associated with the thread. */
|
||||
Entry &remove_entry = remove->GetSleepingQueueEntry();
|
||||
|
||||
/* Get the entries associated with next and prev. */
|
||||
KThread *prev = remove_entry.GetPrev();
|
||||
KThread *next = remove_entry.GetNext();
|
||||
Entry &prev_entry = (prev != nullptr) ? prev->GetSleepingQueueEntry() : this->root;
|
||||
Entry &next_entry = (next != nullptr) ? next->GetSleepingQueueEntry() : this->root;
|
||||
|
||||
/* Unlink. */
|
||||
prev_entry.SetNext(next);
|
||||
next_entry.SetPrev(prev);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue