Kernel: Sleep now actually sleeps and allows idling
This commit is contained in:
@@ -28,7 +28,7 @@ namespace PIT
|
||||
void irq_handler()
|
||||
{
|
||||
s_system_time++;
|
||||
Kernel::Scheduler::get().switch_thread();
|
||||
Kernel::Scheduler::get().reschedule();
|
||||
}
|
||||
|
||||
uint64_t ms_since_boot()
|
||||
@@ -54,7 +54,7 @@ namespace PIT
|
||||
{
|
||||
uint64_t end = s_system_time + ms;
|
||||
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;
|
||||
|
||||
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 continue_thread(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 rip);
|
||||
extern "C" uintptr_t read_rip();
|
||||
|
||||
void Scheduler::initialize()
|
||||
{
|
||||
ASSERT(!s_instance);
|
||||
s_instance = new Scheduler();
|
||||
ASSERT(s_instance);
|
||||
MUST(s_instance->add_thread(BAN::Function<void()>([] { for(;;) asm volatile("hlt"); })));
|
||||
}
|
||||
|
||||
Scheduler& Scheduler::get()
|
||||
@@ -28,72 +30,92 @@ namespace Kernel
|
||||
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()
|
||||
{
|
||||
uintptr_t rsp, rbp, rip;
|
||||
uintptr_t rsp, rip;
|
||||
push_callee_saved();
|
||||
if (!(rip = read_rip()))
|
||||
{
|
||||
pop_callee_saved();
|
||||
return;
|
||||
}
|
||||
read_rsp(rsp);
|
||||
read_rbp(rbp);
|
||||
|
||||
static uint8_t cnt = 0;
|
||||
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();
|
||||
|
||||
ASSERT(m_threads.size() > 1);
|
||||
|
||||
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)
|
||||
{
|
||||
// NOTE: this does not invalidate the next/next_iterator
|
||||
// since we are working with linked list
|
||||
m_threads.remove(m_current_iterator);
|
||||
m_current_iterator = decltype(m_threads)::iterator();
|
||||
m_current_iterator = m_threads.begin();
|
||||
}
|
||||
|
||||
if (m_current_iterator)
|
||||
else
|
||||
{
|
||||
current.set_rsp(rsp);
|
||||
current.set_rbp(rbp);
|
||||
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;
|
||||
|
||||
if (next.state() == Thread::State::NotStarted)
|
||||
switch (next.state())
|
||||
{
|
||||
InterruptController::get().eoi(PIT_IRQ);
|
||||
next.set_state(Thread::State::Running);
|
||||
const uintptr_t* args = next.args();
|
||||
start_thread(args[0], args[1], args[2], args[3], next.rsp(), next.rbp(), next.rip());
|
||||
}
|
||||
else if (next.state() == Thread::State::Paused)
|
||||
{
|
||||
next.set_state(Thread::State::Running);
|
||||
continue_thread(next.rsp(), next.rbp(), next.rip());
|
||||
case Thread::State::NotStarted:
|
||||
next.set_state(Thread::State::Running);
|
||||
start_thread(next.args()[0], next.args()[1], next.args()[2], next.args()[3], next.rsp(), next.rip());
|
||||
break;
|
||||
case Thread::State::Paused:
|
||||
next.set_state(Thread::State::Running);
|
||||
continue_thread(next.rsp(), next.rip());
|
||||
break;
|
||||
case Thread::State::Sleeping: ASSERT(false);
|
||||
case Thread::State::Running: ASSERT(false);
|
||||
case Thread::State::Done: 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()
|
||||
{
|
||||
ASSERT(m_threads.size() > 0);
|
||||
ASSERT(m_threads.size() > 1);
|
||||
|
||||
m_current_iterator = m_threads.begin();
|
||||
|
||||
@@ -102,7 +124,7 @@ namespace Kernel
|
||||
current.set_state(Thread::State::Running);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
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>
|
||||
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);
|
||||
ASSERT(m_stack_base);
|
||||
|
||||
m_rbp = (uintptr_t)m_stack_base + thread_stack_size;
|
||||
m_rsp = m_rbp;
|
||||
m_rsp = (uintptr_t)m_stack_base + thread_stack_size;
|
||||
m_rip = rip;
|
||||
m_args[1] = arg1;
|
||||
m_args[2] = arg2;
|
||||
@@ -54,8 +53,10 @@ namespace Kernel
|
||||
|
||||
void Thread::on_exit()
|
||||
{
|
||||
asm volatile("cli");
|
||||
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& scheduler = Scheduler::get();
|
||||
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()>([] { DiskIO::initialize(); })));
|
||||
MUST(scheduler.add_thread(BAN::Function<void()>([tty1] { Shell(tty1).run(); })));
|
||||
scheduler.start();
|
||||
ASSERT(false);
|
||||
}
|
||||
Reference in New Issue
Block a user