142 lines
2.9 KiB
C++
142 lines
2.9 KiB
C++
#pragma once
|
|
|
|
#include <BAN/Array.h>
|
|
#include <BAN/ForwardList.h>
|
|
#include <BAN/NoCopyMove.h>
|
|
#include <kernel/InterruptStack.h>
|
|
#include <kernel/ProcessorID.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
namespace Kernel
|
|
{
|
|
|
|
class Thread;
|
|
class ThreadBlocker;
|
|
|
|
class SchedulerQueue
|
|
{
|
|
public:
|
|
struct Node
|
|
{
|
|
Node(Thread* thread)
|
|
: thread(thread)
|
|
{}
|
|
|
|
Thread* const thread;
|
|
|
|
Node* next { nullptr };
|
|
Node* prev { nullptr };
|
|
|
|
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
|
|
|
ThreadBlocker* blocker { nullptr };
|
|
Node* block_chain_next { nullptr };
|
|
Node* block_chain_prev { nullptr };
|
|
|
|
ProcessorID processor_id { PROCESSOR_NONE };
|
|
bool blocked { false };
|
|
|
|
uint64_t last_start_ns { 0 };
|
|
uint64_t time_used_ns { 0 };
|
|
};
|
|
|
|
public:
|
|
void add_thread_to_back(Node*);
|
|
void add_thread_with_wake_time(Node*);
|
|
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);
|
|
BAN_NON_MOVABLE(Scheduler);
|
|
|
|
public:
|
|
struct NewThreadRequest
|
|
{
|
|
SchedulerQueue::Node* node;
|
|
};
|
|
|
|
struct UnblockRequest
|
|
{
|
|
SchedulerQueue::Node* node;
|
|
};
|
|
|
|
public:
|
|
static BAN::ErrorOr<Scheduler*> create();
|
|
BAN::ErrorOr<void> initialize();
|
|
|
|
void reschedule(InterruptStack*, InterruptRegisters*);
|
|
void reschedule_if_idle();
|
|
|
|
void timer_interrupt();
|
|
|
|
BAN::ErrorOr<void> add_thread(Thread*);
|
|
|
|
void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns);
|
|
void unblock_thread(Thread*);
|
|
|
|
Thread& current_thread();
|
|
Thread& idle_thread();
|
|
|
|
pid_t current_tid() const;
|
|
bool is_idle() const;
|
|
|
|
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 do_load_balancing();
|
|
|
|
class ProcessorID find_least_loaded_processor() const;
|
|
|
|
void add_thread(SchedulerQueue::Node*);
|
|
void unblock_thread(SchedulerQueue::Node*);
|
|
|
|
private:
|
|
SchedulerQueue m_run_queue;
|
|
SchedulerQueue m_block_queue;
|
|
SchedulerQueue::Node* m_current { nullptr };
|
|
|
|
uint32_t m_thread_count { 0 };
|
|
|
|
InterruptStack* m_interrupt_stack { nullptr };
|
|
InterruptRegisters* m_interrupt_registers { nullptr };
|
|
|
|
uint64_t m_last_reschedule_ns { 0 };
|
|
uint64_t m_last_load_balance_ns { 0 };
|
|
|
|
struct ThreadInfo
|
|
{
|
|
SchedulerQueue* queue { nullptr };
|
|
SchedulerQueue::Node* node { nullptr };
|
|
};
|
|
BAN::Array<ThreadInfo, 10> m_most_loaded_threads;
|
|
|
|
uint64_t m_idle_start_ns { 0 };
|
|
uint64_t m_idle_ns { 0 };
|
|
|
|
bool m_should_calculate_max_load_threads { true };
|
|
|
|
Thread* m_idle_thread { nullptr };
|
|
|
|
friend class ThreadBlocker;
|
|
friend class Processor;
|
|
};
|
|
|
|
}
|