Kernel: Sleep now actually sleeps and allows idling
This commit is contained in:
parent
66a4b69a29
commit
1bd8b0fe5c
|
@ -129,7 +129,9 @@ found:
|
||||||
else
|
else
|
||||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||||
|
|
||||||
InterruptController::get().eoi(irq);
|
// NOTE: Scheduler sends PIT eoi's
|
||||||
|
if (irq != PIT_IRQ)
|
||||||
|
InterruptController::get().eoi(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void handle_irq_common();
|
extern "C" void handle_irq_common();
|
||||||
|
|
|
@ -11,12 +11,11 @@ exit_thread_trampoline:
|
||||||
pushl %eax
|
pushl %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rbp, uint32_t rip)
|
# void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rip)
|
||||||
.global start_thread
|
.global start_thread
|
||||||
start_thread:
|
start_thread:
|
||||||
movl %esp, %eax
|
movl %esp, %eax
|
||||||
movl 28(%eax), %ecx
|
movl 24(%eax), %ecx
|
||||||
movl 24(%eax), %ebp
|
|
||||||
movl 20(%eax), %esp
|
movl 20(%eax), %esp
|
||||||
|
|
||||||
pushl 16(%eax)
|
pushl 16(%eax)
|
||||||
|
@ -25,14 +24,15 @@ start_thread:
|
||||||
pushl 4(%eax)
|
pushl 4(%eax)
|
||||||
pushl $exit_thread_trampoline
|
pushl $exit_thread_trampoline
|
||||||
|
|
||||||
|
movl $0, %ebp
|
||||||
|
|
||||||
sti
|
sti
|
||||||
jmp *%ecx
|
jmp *%ecx
|
||||||
|
|
||||||
# void continue_thread(uint32_t rsp, uint32_t rbp, uint32_t rip)
|
# void continue_thread(uint32_t rsp, uint32_t rip)
|
||||||
.global continue_thread
|
.global continue_thread
|
||||||
continue_thread:
|
continue_thread:
|
||||||
movl 12(%esp), %ecx
|
movl 8(%esp), %ecx
|
||||||
movl 8(%esp), %ebp
|
|
||||||
movl 4(%esp), %esp
|
movl 4(%esp), %esp
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
jmp *%ecx
|
jmp *%ecx
|
|
@ -126,7 +126,9 @@ namespace IDT
|
||||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
InterruptController::get().eoi(irq);
|
// NOTE: Scheduler sends PIT eoi's
|
||||||
|
if (irq != PIT_IRQ)
|
||||||
|
InterruptController::get().eoi(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_idt()
|
static void flush_idt()
|
||||||
|
|
|
@ -8,20 +8,18 @@ exit_thread_trampoline:
|
||||||
movq 8(%rsp), %rdi
|
movq 8(%rsp), %rdi
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rbp, uint64_t rip)
|
# void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rip)
|
||||||
.global start_thread
|
.global start_thread
|
||||||
start_thread:
|
start_thread:
|
||||||
movq 8(%rsp), %rcx
|
|
||||||
movq %r8, %rsp
|
movq %r8, %rsp
|
||||||
movq %r9, %rbp
|
movq $0, %rbp
|
||||||
pushq $exit_thread_trampoline
|
pushq $exit_thread_trampoline
|
||||||
sti
|
sti
|
||||||
jmp *%rcx
|
jmp *%r9
|
||||||
|
|
||||||
# void continue_thread(uint64_t rsp, uint64_t rbp, uint64_t rip)
|
# void continue_thread(uint64_t rsp, uint64_t rip)
|
||||||
.global continue_thread
|
.global continue_thread
|
||||||
continue_thread:
|
continue_thread:
|
||||||
movq %rdi, %rsp
|
movq %rdi, %rsp
|
||||||
movq %rsi, %rbp
|
|
||||||
movq $0, %rax
|
movq $0, %rax
|
||||||
jmp *%rdx
|
jmp *%rsi
|
|
@ -19,27 +19,33 @@ namespace Kernel
|
||||||
const Thread& current_thread() const;
|
const Thread& current_thread() const;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void add_thread(const BAN::Function<void(Args...)>& func, Args... args)
|
[[nodiscard]] BAN::ErrorOr<void> add_thread(const BAN::Function<void(Args...)>& func, Args... args)
|
||||||
{
|
{
|
||||||
uintptr_t flags;
|
uintptr_t flags;
|
||||||
asm volatile("pushf; pop %0" : "=r"(flags));
|
asm volatile("pushf; pop %0" : "=r"(flags));
|
||||||
asm volatile("cli");
|
asm volatile("cli");
|
||||||
MUST(m_threads.emplace_back(func, BAN::forward<Args>(args)...));
|
TRY(m_threads.emplace_back(func, BAN::forward<Args>(args)...));
|
||||||
if (flags & (1 << 9))
|
if (flags & (1 << 9))
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_thread();
|
void reschedule();
|
||||||
|
void set_current_thread_sleeping();
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
static constexpr size_t ms_between_switch = 1;
|
static constexpr size_t ms_between_switch = 4;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scheduler() {}
|
Scheduler() {}
|
||||||
|
void switch_thread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::LinkedList<Thread> m_threads;
|
BAN::LinkedList<Thread> m_threads;
|
||||||
BAN::LinkedList<Thread>::iterator m_current_iterator;
|
BAN::LinkedList<Thread>::iterator m_current_iterator;
|
||||||
|
uint64_t m_last_reschedule = 0;
|
||||||
|
|
||||||
|
friend class Thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@ namespace Kernel
|
||||||
NotStarted,
|
NotStarted,
|
||||||
Running,
|
Running,
|
||||||
Paused,
|
Paused,
|
||||||
|
Sleeping,
|
||||||
Done,
|
Done,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,11 +37,9 @@ namespace Kernel
|
||||||
uint32_t id() const { return m_id; }
|
uint32_t id() const { return m_id; }
|
||||||
|
|
||||||
void set_rsp(uintptr_t rsp) { m_rsp = rsp; }
|
void set_rsp(uintptr_t rsp) { m_rsp = rsp; }
|
||||||
void set_rbp(uintptr_t rbp) { m_rbp = rbp; }
|
|
||||||
void set_rip(uintptr_t rip) { m_rip = rip; }
|
void set_rip(uintptr_t rip) { m_rip = rip; }
|
||||||
void set_state(State state) { m_state = state; }
|
void set_state(State state) { m_state = state; }
|
||||||
uintptr_t rsp() const { return m_rsp; }
|
uintptr_t rsp() const { return m_rsp; }
|
||||||
uintptr_t rbp() const { return m_rbp; }
|
|
||||||
uintptr_t rip() const { return m_rip; }
|
uintptr_t rip() const { return m_rip; }
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
|
|
||||||
|
@ -55,7 +54,6 @@ namespace Kernel
|
||||||
State m_state = State::NotStarted;
|
State m_state = State::NotStarted;
|
||||||
uintptr_t m_args[4] = {};
|
uintptr_t m_args[4] = {};
|
||||||
uintptr_t m_rip = 0;
|
uintptr_t m_rip = 0;
|
||||||
uintptr_t m_rbp = 0;
|
|
||||||
uintptr_t m_rsp = 0;
|
uintptr_t m_rsp = 0;
|
||||||
const uint32_t m_id = 0;
|
const uint32_t m_id = 0;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace PIT
|
||||||
void irq_handler()
|
void irq_handler()
|
||||||
{
|
{
|
||||||
s_system_time++;
|
s_system_time++;
|
||||||
Kernel::Scheduler::get().switch_thread();
|
Kernel::Scheduler::get().reschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ms_since_boot()
|
uint64_t ms_since_boot()
|
||||||
|
@ -54,7 +54,7 @@ namespace PIT
|
||||||
{
|
{
|
||||||
uint64_t end = s_system_time + ms;
|
uint64_t end = s_system_time + ms;
|
||||||
while (s_system_time < end)
|
while (s_system_time < end)
|
||||||
asm volatile("hlt");
|
Kernel::Scheduler::get().set_current_thread_sleeping();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,16 @@ namespace Kernel
|
||||||
|
|
||||||
static Scheduler* s_instance = nullptr;
|
static Scheduler* s_instance = nullptr;
|
||||||
|
|
||||||
extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rbp, uintptr_t rip);
|
extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rip);
|
||||||
extern "C" void continue_thread(uintptr_t rsp, uintptr_t rbp, uintptr_t rip);
|
extern "C" void continue_thread(uintptr_t rsp, uintptr_t rip);
|
||||||
extern "C" uintptr_t read_rip();
|
extern "C" uintptr_t read_rip();
|
||||||
|
|
||||||
void Scheduler::initialize()
|
void Scheduler::initialize()
|
||||||
{
|
{
|
||||||
ASSERT(!s_instance);
|
ASSERT(!s_instance);
|
||||||
s_instance = new Scheduler();
|
s_instance = new Scheduler();
|
||||||
|
ASSERT(s_instance);
|
||||||
|
MUST(s_instance->add_thread(BAN::Function<void()>([] { for(;;) asm volatile("hlt"); })));
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheduler& Scheduler::get()
|
Scheduler& Scheduler::get()
|
||||||
|
@ -28,72 +30,92 @@ namespace Kernel
|
||||||
return *m_current_iterator;
|
return *m_current_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::reschedule()
|
||||||
|
{
|
||||||
|
ASSERT(InterruptController::get().is_in_service(PIT_IRQ));
|
||||||
|
InterruptController::get().eoi(PIT_IRQ);
|
||||||
|
|
||||||
|
uint64_t current_time = PIT::ms_since_boot();
|
||||||
|
if (m_last_reschedule + ms_between_switch > current_time)
|
||||||
|
return;
|
||||||
|
m_last_reschedule = current_time;
|
||||||
|
|
||||||
|
for (Thread& thread : m_threads)
|
||||||
|
if (thread.state() == Thread::State::Sleeping)
|
||||||
|
thread.set_state(Thread::State::Paused);
|
||||||
|
|
||||||
|
switch_thread();
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::switch_thread()
|
void Scheduler::switch_thread()
|
||||||
{
|
{
|
||||||
uintptr_t rsp, rbp, rip;
|
uintptr_t rsp, rip;
|
||||||
|
push_callee_saved();
|
||||||
if (!(rip = read_rip()))
|
if (!(rip = read_rip()))
|
||||||
|
{
|
||||||
|
pop_callee_saved();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
read_rsp(rsp);
|
read_rsp(rsp);
|
||||||
read_rbp(rbp);
|
|
||||||
|
|
||||||
static uint8_t cnt = 0;
|
ASSERT(m_threads.size() > 1);
|
||||||
if (cnt++ % ms_between_switch)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ASSERT(InterruptController::get().is_in_service(PIT_IRQ));
|
|
||||||
|
|
||||||
ASSERT(m_threads.size() > 0);
|
|
||||||
if (m_threads.size() == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ASSERT(m_current_iterator);
|
|
||||||
|
|
||||||
auto next_iterator = m_current_iterator;
|
|
||||||
if (++next_iterator == m_threads.end())
|
|
||||||
next_iterator = m_threads.begin();
|
|
||||||
|
|
||||||
Thread& current = *m_current_iterator;
|
Thread& current = *m_current_iterator;
|
||||||
Thread& next = *next_iterator;
|
|
||||||
|
|
||||||
ASSERT(next.state() == Thread::State::Paused || next.state() == Thread::State::NotStarted);
|
//if (m_threads.size() == 2 && current.id() != 0 && current.state() == Thread::State::Running)
|
||||||
|
// return;
|
||||||
|
|
||||||
if (current.state() == Thread::State::Done)
|
if (current.state() == Thread::State::Done)
|
||||||
{
|
{
|
||||||
// NOTE: this does not invalidate the next/next_iterator
|
|
||||||
// since we are working with linked list
|
|
||||||
m_threads.remove(m_current_iterator);
|
m_threads.remove(m_current_iterator);
|
||||||
m_current_iterator = decltype(m_threads)::iterator();
|
m_current_iterator = m_threads.begin();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (m_current_iterator)
|
|
||||||
{
|
{
|
||||||
current.set_rsp(rsp);
|
current.set_rsp(rsp);
|
||||||
current.set_rbp(rbp);
|
|
||||||
current.set_rip(rip);
|
current.set_rip(rip);
|
||||||
current.set_state(Thread::State::Paused);
|
if (current.state() != Thread::State::Sleeping)
|
||||||
|
current.set_state(Thread::State::Paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto next_iterator = m_current_iterator;
|
||||||
|
if (++next_iterator == m_threads.end())
|
||||||
|
next_iterator = ++m_threads.begin();
|
||||||
|
if (next_iterator->state() == Thread::State::Sleeping)
|
||||||
|
next_iterator = m_threads.begin();
|
||||||
|
Thread& next = *next_iterator;
|
||||||
|
|
||||||
m_current_iterator = next_iterator;
|
m_current_iterator = next_iterator;
|
||||||
|
|
||||||
if (next.state() == Thread::State::NotStarted)
|
switch (next.state())
|
||||||
{
|
{
|
||||||
InterruptController::get().eoi(PIT_IRQ);
|
case Thread::State::NotStarted:
|
||||||
next.set_state(Thread::State::Running);
|
next.set_state(Thread::State::Running);
|
||||||
const uintptr_t* args = next.args();
|
start_thread(next.args()[0], next.args()[1], next.args()[2], next.args()[3], next.rsp(), next.rip());
|
||||||
start_thread(args[0], args[1], args[2], args[3], next.rsp(), next.rbp(), next.rip());
|
break;
|
||||||
}
|
case Thread::State::Paused:
|
||||||
else if (next.state() == Thread::State::Paused)
|
next.set_state(Thread::State::Running);
|
||||||
{
|
continue_thread(next.rsp(), next.rip());
|
||||||
next.set_state(Thread::State::Running);
|
break;
|
||||||
continue_thread(next.rsp(), next.rbp(), next.rip());
|
case Thread::State::Sleeping: ASSERT(false);
|
||||||
|
case Thread::State::Running: ASSERT(false);
|
||||||
|
case Thread::State::Done: ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::set_current_thread_sleeping()
|
||||||
|
{
|
||||||
|
asm volatile("cli");
|
||||||
|
m_current_iterator->set_state(Thread::State::Sleeping);
|
||||||
|
switch_thread();
|
||||||
|
asm volatile("sti");
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::start()
|
void Scheduler::start()
|
||||||
{
|
{
|
||||||
ASSERT(m_threads.size() > 0);
|
ASSERT(m_threads.size() > 1);
|
||||||
|
|
||||||
m_current_iterator = m_threads.begin();
|
m_current_iterator = m_threads.begin();
|
||||||
|
|
||||||
|
@ -102,7 +124,7 @@ namespace Kernel
|
||||||
current.set_state(Thread::State::Running);
|
current.set_state(Thread::State::Running);
|
||||||
|
|
||||||
const uintptr_t* args = current.args();
|
const uintptr_t* args = current.args();
|
||||||
start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rbp(), current.rip());
|
start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rip());
|
||||||
|
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static uint32_t s_next_id = 1;
|
static uint32_t s_next_id = 0;
|
||||||
|
|
||||||
static constexpr size_t thread_stack_size = PAGE_SIZE;
|
static constexpr size_t thread_stack_size = 16384;
|
||||||
|
|
||||||
template<size_t size, typename T>
|
template<size_t size, typename T>
|
||||||
static void write_to_stack(uintptr_t& rsp, const T& value)
|
static void write_to_stack(uintptr_t& rsp, const T& value)
|
||||||
|
@ -27,8 +27,7 @@ namespace Kernel
|
||||||
m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE);
|
m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE);
|
||||||
ASSERT(m_stack_base);
|
ASSERT(m_stack_base);
|
||||||
|
|
||||||
m_rbp = (uintptr_t)m_stack_base + thread_stack_size;
|
m_rsp = (uintptr_t)m_stack_base + thread_stack_size;
|
||||||
m_rsp = m_rbp;
|
|
||||||
m_rip = rip;
|
m_rip = rip;
|
||||||
m_args[1] = arg1;
|
m_args[1] = arg1;
|
||||||
m_args[2] = arg2;
|
m_args[2] = arg2;
|
||||||
|
@ -54,8 +53,10 @@ namespace Kernel
|
||||||
|
|
||||||
void Thread::on_exit()
|
void Thread::on_exit()
|
||||||
{
|
{
|
||||||
|
asm volatile("cli");
|
||||||
m_state = State::Done;
|
m_state = State::Done;
|
||||||
for (;;) asm volatile("hlt");
|
Scheduler::get().switch_thread();
|
||||||
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -97,8 +97,8 @@ extern "C" void kernel_main()
|
||||||
|
|
||||||
Scheduler::initialize();
|
Scheduler::initialize();
|
||||||
Scheduler& scheduler = Scheduler::get();
|
Scheduler& scheduler = Scheduler::get();
|
||||||
scheduler.add_thread(BAN::Function<void()>([] { DiskIO::initialize(); }));
|
MUST(scheduler.add_thread(BAN::Function<void()>([] { DiskIO::initialize(); })));
|
||||||
scheduler.add_thread(BAN::Function<void()>([tty1] { Shell(tty1).run(); }));
|
MUST(scheduler.add_thread(BAN::Function<void()>([tty1] { Shell(tty1).run(); })));
|
||||||
scheduler.start();
|
scheduler.start();
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
Loading…
Reference in New Issue