Kernel: Use min heap for scheduler block list

This makes insertion to block list O(log n) instead of O(n) when
blocking with wake time. This is more heavy and currently slower than
the previous implementation, but that is just because we don't really
have too many threads running at any given time. This will be more
scalable in the future and even allows implementing priorities if I ever
wish so
This commit is contained in:
2026-08-19 21:32:36 +03:00
parent 7f12e5aaf3
commit 2f25bfb2db
10 changed files with 446 additions and 210 deletions
+3 -3
View File
@@ -22,7 +22,7 @@ namespace Kernel
class GDT;
class IDT;
class Scheduler;
class SchedulerQueueNode;
class SchedulerThreadNode;
class Thread;
#if ARCH(x86_64) || ARCH(i686)
@@ -54,8 +54,8 @@ namespace Kernel
union
{
TLBEntry flush_tlb;
SchedulerQueueNode* new_thread;
SchedulerQueueNode* unblock_thread;
SchedulerThreadNode* new_thread;
SchedulerThreadNode* unblock_thread;
bool dummy;
};
};
+13 -35
View File
@@ -5,6 +5,7 @@
#include <BAN/NoCopyMove.h>
#include <kernel/InterruptStack.h>
#include <kernel/ProcessorID.h>
#include <kernel/SchedulerThreadNode.h>
#include <sys/types.h>
@@ -14,29 +15,6 @@ namespace Kernel
class BaseMutex;
class Thread;
class ThreadBlocker;
struct SchedulerQueueNode;
class SchedulerQueue
{
public:
using Node = SchedulerQueueNode;
public:
void add_thread_to_back(Node*);
bool add_thread_with_wake_time(Node*); // return true if node was inserted as the first element
template<typename F>
Node* remove_with_condition(F callback);
void remove_node(Node*);
Node* front();
Node* pop_front();
bool empty() const { return m_head == nullptr; }
private:
Node* m_head { nullptr };
Node* m_tail { nullptr };
};
class Scheduler
{
BAN_NON_COPYABLE(Scheduler);
@@ -45,12 +23,12 @@ namespace Kernel
public:
struct NewThreadRequest
{
SchedulerQueue::Node* node;
SchedulerThreadNode* node;
};
struct UnblockRequest
{
SchedulerQueue::Node* node;
SchedulerThreadNode* node;
};
public:
@@ -79,9 +57,9 @@ namespace Kernel
private:
Scheduler() = default;
void add_current_to_most_loaded(SchedulerQueue* target_queue);
void update_most_loaded_node_queue(SchedulerQueue::Node*, SchedulerQueue* target_queue);
void remove_node_from_most_loaded(SchedulerQueue::Node*);
void add_current_to_most_loaded(void* target_list);
void update_most_loaded_node_list(SchedulerThreadNode*, void* target_list);
void remove_node_from_most_loaded(SchedulerThreadNode*);
void update_wake_up_deadline();
void wake_up_sleeping_threads();
@@ -90,13 +68,13 @@ namespace Kernel
class ProcessorID find_least_loaded_processor() const;
void add_thread(SchedulerQueue::Node*);
void unblock_thread(SchedulerQueue::Node*);
void add_thread(SchedulerThreadNode*);
void unblock_thread(SchedulerThreadNode*);
private:
SchedulerQueue m_run_queue;
SchedulerQueue m_block_queue;
SchedulerQueue::Node* m_current { nullptr };
SchedulerQueue m_run_list;
SchedulerHeap m_block_list;
SchedulerThreadNode* m_current { nullptr };
uint32_t m_thread_count { 0 };
@@ -108,8 +86,8 @@ namespace Kernel
struct ThreadInfo
{
SchedulerQueue* queue { nullptr };
SchedulerQueue::Node* node { nullptr };
void* list { nullptr };
SchedulerThreadNode* node { nullptr };
};
BAN::Array<ThreadInfo, 10> m_most_loaded_threads;
@@ -1,36 +0,0 @@
#pragma once
#include <BAN/Atomic.h>
#include <kernel/ProcessorID.h>
namespace Kernel
{
class Thread;
class ThreadBlocker;
struct SchedulerQueueNode
{
SchedulerQueueNode(Thread* thread)
: thread(thread)
{}
Thread* const thread;
SchedulerQueueNode* next { nullptr };
SchedulerQueueNode* prev { nullptr };
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
SchedulerQueueNode* block_chain_prev { nullptr };
SchedulerQueueNode* block_chain_next { nullptr };
ProcessorID processor_id { PROCESSOR_NONE };
bool blocked { false };
uint64_t last_start_ns { 0 };
uint64_t time_used_ns { 0 };
};
}
@@ -0,0 +1,96 @@
#pragma once
#include <BAN/Atomic.h>
#include <BAN/NoCopyMove.h>
#include <kernel/ProcessorID.h>
namespace Kernel
{
class Thread;
class ThreadBlocker;
struct SchedulerThreadNode
{
SchedulerThreadNode(Thread* thread)
: thread(thread)
, heap({ nullptr, nullptr, nullptr })
{}
Thread* const thread;
union
{
struct
{
SchedulerThreadNode* next;
SchedulerThreadNode* prev;
} queue;
struct
{
SchedulerThreadNode* parent;
SchedulerThreadNode* lchild;
SchedulerThreadNode* rchild;
} heap;
};
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
SchedulerThreadNode* block_chain_prev { nullptr };
SchedulerThreadNode* block_chain_next { nullptr };
ProcessorID processor_id { PROCESSOR_NONE };
bool blocked { false };
uint64_t last_start_ns { 0 };
uint64_t time_used_ns { 0 };
};
class SchedulerQueue
{
BAN_NON_COPYABLE(SchedulerQueue);
BAN_NON_MOVABLE(SchedulerQueue);
public:
SchedulerQueue() = default;
SchedulerThreadNode* front();
SchedulerThreadNode* pop_front();
void push(SchedulerThreadNode*);
void pop(SchedulerThreadNode*);
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
bool empty() const { return m_head == nullptr; }
private:
SchedulerThreadNode* m_head { nullptr };
SchedulerThreadNode* m_tail { nullptr };
};
class SchedulerHeap
{
BAN_NON_COPYABLE(SchedulerHeap);
BAN_NON_MOVABLE(SchedulerHeap);
public:
SchedulerHeap() = default;
SchedulerThreadNode* front();
SchedulerThreadNode* pop_front();
void push(SchedulerThreadNode*);
void pop(SchedulerThreadNode*);
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
bool empty() const { return m_root == nullptr; }
private:
void walk_impl(void (*)(const SchedulerThreadNode*, void*), void*, const SchedulerThreadNode*) const;
void swap_nodes(SchedulerThreadNode*, SchedulerThreadNode*);
private:
SchedulerThreadNode* m_root { nullptr };
SchedulerThreadNode* m_last { nullptr };
};
}
+1 -1
View File
@@ -192,7 +192,7 @@ namespace Kernel
vaddr_t m_fsbase { 0 };
vaddr_t m_gsbase { 0 };
SchedulerQueueNode* m_scheduler_node { nullptr };
SchedulerThreadNode* m_scheduler_node { nullptr };
YieldRegisters m_yield_registers { };
+4 -4
View File
@@ -7,7 +7,7 @@
namespace Kernel
{
class SchedulerQueueNode;
class SchedulerThreadNode;
class ThreadBlocker
{
@@ -29,11 +29,11 @@ namespace Kernel
}
private:
void add_thread_to_block_queue(SchedulerQueueNode*);
void remove_thread_from_block_queue(SchedulerQueueNode*);
void add_thread_to_block_queue(SchedulerThreadNode*);
void remove_thread_from_block_queue(SchedulerThreadNode*);
private:
SchedulerQueueNode* m_block_chain { nullptr };
SchedulerThreadNode* m_block_chain { nullptr };
SpinLock m_lock;
friend class Scheduler;