Kernel: Replace last CriticalScopes in kernel with SpinLocks
This commit is contained in:
parent
054b41383f
commit
8d7dd577ab
|
@ -30,9 +30,12 @@ namespace Kernel
|
|||
static pid_t current_tid();
|
||||
|
||||
[[noreturn]] void execute_current_thread();
|
||||
[[noreturn]] void _execute_current_thread();
|
||||
[[noreturn]] void execute_current_thread_locked();
|
||||
[[noreturn]] void delete_current_process_and_thread();
|
||||
|
||||
// This is no return if called on current thread
|
||||
void terminate_thread(Thread*);
|
||||
|
||||
private:
|
||||
Scheduler() = default;
|
||||
|
||||
|
@ -43,6 +46,8 @@ namespace Kernel
|
|||
void remove_and_advance_current_thread();
|
||||
void advance_current_thread();
|
||||
|
||||
[[noreturn]] void execute_current_thread_stack_loaded();
|
||||
|
||||
BAN::ErrorOr<void> add_thread(Thread*);
|
||||
|
||||
private:
|
||||
|
@ -57,6 +62,8 @@ namespace Kernel
|
|||
Semaphore* semaphore;
|
||||
};
|
||||
|
||||
SpinLockUnsafe m_lock;
|
||||
|
||||
Thread* m_idle_thread { nullptr };
|
||||
BAN::LinkedList<SchedulerThread> m_active_threads;
|
||||
BAN::LinkedList<SchedulerThread> m_sleeping_threads;
|
||||
|
|
|
@ -65,8 +65,6 @@ namespace Kernel
|
|||
uintptr_t rip() const { return m_rip; }
|
||||
|
||||
void set_started() { ASSERT(m_state == State::NotStarted); m_state = State::Executing; }
|
||||
// Thread will no longer execute. If called on current thread, does not return
|
||||
void terminate();
|
||||
State state() const { return m_state; }
|
||||
|
||||
vaddr_t stack_base() const { return m_stack->vaddr(); }
|
||||
|
|
|
@ -230,7 +230,8 @@ namespace Kernel
|
|||
m_threads.clear();
|
||||
|
||||
thread.setup_process_cleanup();
|
||||
Scheduler::get().execute_current_thread();
|
||||
// NOTE: This function is only called from scheduler when it is already locked
|
||||
Scheduler::get().execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
@ -252,9 +253,9 @@ namespace Kernel
|
|||
m_exit_status.exit_code = __WGENEXITCODE(status, signal);
|
||||
for (auto* thread : m_threads)
|
||||
if (thread != &Thread::current())
|
||||
thread->terminate();
|
||||
Scheduler::get().terminate_thread(thread);
|
||||
if (this == &Process::current())
|
||||
Thread::current().terminate();
|
||||
Scheduler::get().terminate_thread(&Thread::current());
|
||||
}
|
||||
|
||||
size_t Process::proc_meminfo(off_t offset, BAN::ByteSpan buffer) const
|
||||
|
@ -330,8 +331,8 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> Process::sys_exit(int status)
|
||||
{
|
||||
ASSERT(this == &Process::current());
|
||||
exit(status, 0);
|
||||
Thread::current().terminate();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <kernel/Arch.h>
|
||||
#include <kernel/Attributes.h>
|
||||
#include <kernel/CriticalScope.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Process.h>
|
||||
|
@ -8,15 +7,6 @@
|
|||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#define SCHEDULER_VERIFY_STACK 1
|
||||
#define SCHEDULER_VERIFY_INTERRUPT_STATE 1
|
||||
|
||||
#if SCHEDULER_VERIFY_INTERRUPT_STATE
|
||||
#define VERIFY_STI() ASSERT(get_interrupt_state() == InterruptState::Enabled)
|
||||
#define VERIFY_CLI() ASSERT(get_interrupt_state() == InterruptState::Disabled)
|
||||
#else
|
||||
#define VERIFY_STI()
|
||||
#define VERIFY_CLI()
|
||||
#endif
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -50,10 +40,11 @@ namespace Kernel
|
|||
|
||||
void Scheduler::start()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
ASSERT(get_interrupt_state() == InterruptState::Disabled);
|
||||
m_lock.lock();
|
||||
ASSERT(!m_active_threads.empty());
|
||||
m_current_thread = m_active_threads.begin();
|
||||
execute_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
@ -71,45 +62,40 @@ namespace Kernel
|
|||
|
||||
void Scheduler::timer_reschedule()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
|
||||
auto state = m_lock.lock();
|
||||
wake_threads();
|
||||
|
||||
if (save_current_thread())
|
||||
return;
|
||||
return m_lock.unlock(state);
|
||||
advance_current_thread();
|
||||
execute_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Scheduler::reschedule()
|
||||
{
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
auto state = m_lock.lock();
|
||||
if (save_current_thread())
|
||||
return set_interrupt_state(InterruptState::Enabled);
|
||||
return set_interrupt_state(state);
|
||||
advance_current_thread();
|
||||
execute_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Scheduler::reschedule_if_idling()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
|
||||
auto state = m_lock.lock();
|
||||
if (m_active_threads.empty() || ¤t_thread() != m_idle_thread)
|
||||
return;
|
||||
|
||||
return m_lock.unlock(state);
|
||||
if (save_current_thread())
|
||||
return;
|
||||
return m_lock.unlock(state);
|
||||
m_current_thread = m_active_threads.begin();
|
||||
execute_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Scheduler::wake_threads()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
ASSERT(m_lock.is_locked());
|
||||
|
||||
uint64_t current_time = SystemTimer::get().ms_since_boot();
|
||||
while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time)
|
||||
|
@ -124,14 +110,22 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> Scheduler::add_thread(Thread* thread)
|
||||
{
|
||||
CriticalScope _;
|
||||
SpinLockGuard _(m_lock);
|
||||
TRY(m_active_threads.emplace_back(thread));
|
||||
return {};
|
||||
}
|
||||
|
||||
void Scheduler::terminate_thread(Thread* thread)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
thread->m_state = Thread::State::Terminated;
|
||||
if (thread == ¤t_thread())
|
||||
execute_current_thread_locked();
|
||||
}
|
||||
|
||||
void Scheduler::advance_current_thread()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
ASSERT(m_lock.is_locked());
|
||||
|
||||
if (m_active_threads.empty())
|
||||
{
|
||||
|
@ -144,7 +138,7 @@ namespace Kernel
|
|||
|
||||
void Scheduler::remove_and_advance_current_thread()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
ASSERT(m_lock.is_locked());
|
||||
|
||||
ASSERT(m_current_thread);
|
||||
|
||||
|
@ -165,7 +159,7 @@ namespace Kernel
|
|||
// after getting the rsp
|
||||
ALWAYS_INLINE bool Scheduler::save_current_thread()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
ASSERT(m_lock.is_locked());
|
||||
|
||||
uintptr_t rsp, rip;
|
||||
push_callee_saved();
|
||||
|
@ -187,7 +181,7 @@ namespace Kernel
|
|||
|
||||
void Scheduler::delete_current_process_and_thread()
|
||||
{
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
m_lock.lock();
|
||||
|
||||
load_temp_stack();
|
||||
PageTable::kernel().load();
|
||||
|
@ -201,23 +195,33 @@ namespace Kernel
|
|||
|
||||
delete thread;
|
||||
|
||||
execute_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Scheduler::execute_current_thread()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
|
||||
m_lock.lock();
|
||||
load_temp_stack();
|
||||
PageTable::kernel().load();
|
||||
_execute_current_thread();
|
||||
execute_current_thread_stack_loaded();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
NEVER_INLINE void Scheduler::_execute_current_thread()
|
||||
void Scheduler::execute_current_thread_locked()
|
||||
{
|
||||
VERIFY_CLI();
|
||||
load_temp_stack();
|
||||
PageTable::kernel().load();
|
||||
execute_current_thread_stack_loaded();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
NEVER_INLINE void Scheduler::execute_current_thread_stack_loaded()
|
||||
{
|
||||
ASSERT(m_lock.is_locked());
|
||||
|
||||
load_temp_stack();
|
||||
PageTable::kernel().load();
|
||||
|
||||
#if SCHEDULER_VERIFY_STACK
|
||||
vaddr_t rsp;
|
||||
|
@ -264,10 +268,12 @@ namespace Kernel
|
|||
{
|
||||
case Thread::State::NotStarted:
|
||||
current->set_started();
|
||||
m_lock.unlock(InterruptState::Disabled);
|
||||
start_thread(current->rsp(), current->rip());
|
||||
case Thread::State::Executing:
|
||||
while (current->can_add_signal_to_execute())
|
||||
current->handle_signal();
|
||||
m_lock.unlock(InterruptState::Disabled);
|
||||
continue_thread(current->rsp(), current->rip());
|
||||
case Thread::State::Terminated:
|
||||
ASSERT_NOT_REACHED();
|
||||
|
@ -278,7 +284,7 @@ namespace Kernel
|
|||
|
||||
void Scheduler::set_current_thread_sleeping_impl(uint64_t wake_time)
|
||||
{
|
||||
VERIFY_CLI();
|
||||
ASSERT(m_lock.is_locked());
|
||||
|
||||
if (save_current_thread())
|
||||
{
|
||||
|
@ -301,35 +307,27 @@ namespace Kernel
|
|||
m_current_thread = {};
|
||||
advance_current_thread();
|
||||
|
||||
execute_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Scheduler::set_current_thread_sleeping(uint64_t wake_time)
|
||||
{
|
||||
VERIFY_STI();
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
ASSERT(m_current_thread);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
m_current_thread->semaphore = nullptr;
|
||||
set_current_thread_sleeping_impl(wake_time);
|
||||
}
|
||||
|
||||
void Scheduler::block_current_thread(Semaphore* semaphore, uint64_t wake_time)
|
||||
{
|
||||
VERIFY_STI();
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
ASSERT(m_current_thread);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
m_current_thread->semaphore = semaphore;
|
||||
set_current_thread_sleeping_impl(wake_time);
|
||||
}
|
||||
|
||||
void Scheduler::unblock_threads(Semaphore* semaphore)
|
||||
{
|
||||
CriticalScope critical;
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
for (auto it = m_sleeping_threads.begin(); it != m_sleeping_threads.end();)
|
||||
{
|
||||
|
@ -350,7 +348,7 @@ namespace Kernel
|
|||
|
||||
void Scheduler::unblock_thread(pid_t tid)
|
||||
{
|
||||
CriticalScope _;
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
for (auto it = m_sleeping_threads.begin(); it != m_sleeping_threads.end(); it++)
|
||||
{
|
||||
|
|
|
@ -27,14 +27,6 @@ namespace Kernel
|
|||
memcpy((void*)rsp, (void*)&value, sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
void Thread::terminate()
|
||||
{
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
m_state = Thread::State::Terminated;
|
||||
if (this == &Thread::current())
|
||||
Scheduler::get().execute_current_thread();
|
||||
}
|
||||
|
||||
static pid_t s_next_tid = 1;
|
||||
|
||||
BAN::ErrorOr<Thread*> Thread::create_kernel(entry_t entry, void* data, Process* process)
|
||||
|
@ -193,9 +185,10 @@ namespace Kernel
|
|||
{
|
||||
m_state = State::NotStarted;
|
||||
static entry_t entry(
|
||||
[](void* process)
|
||||
[](void* process_ptr)
|
||||
{
|
||||
((Process*)process)->cleanup_function();
|
||||
auto& process = *reinterpret_cast<Process*>(process_ptr);
|
||||
process.cleanup_function();
|
||||
Scheduler::get().delete_current_process_and_thread();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
@ -395,7 +388,7 @@ namespace Kernel
|
|||
void Thread::on_exit()
|
||||
{
|
||||
ASSERT(this == &Thread::current());
|
||||
terminate();
|
||||
Scheduler::get().terminate_thread(this);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue