Files
banan-os/kernel/kernel/ThreadBlocker.cpp
T
Bananymous 2f25bfb2db 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
2026-08-19 21:32:36 +03:00

88 lines
2.1 KiB
C++

#include <kernel/Processor.h>
#include <kernel/Scheduler.h>
#include <kernel/SchedulerThreadNode.h>
#include <kernel/ThreadBlocker.h>
#include <kernel/Timer/Timer.h>
namespace Kernel
{
void ThreadBlocker::block_indefinite(BaseMutex* mutex)
{
Processor::scheduler().block_current_thread(this, static_cast<uint64_t>(-1), mutex);
}
void ThreadBlocker::block_with_timeout_ns(uint64_t timeout_ns, BaseMutex* mutex)
{
Processor::scheduler().block_current_thread(this, SystemTimer::get().ns_since_boot() + timeout_ns, mutex);
}
void ThreadBlocker::block_with_wake_time_ns(uint64_t wake_time_ns, BaseMutex* mutex)
{
Processor::scheduler().block_current_thread(this, wake_time_ns, mutex);
}
void ThreadBlocker::unblock()
{
SpinLockGuard _(m_lock);
for (auto* node = m_block_chain; node;)
{
auto* next = node->block_chain_next;
ASSERT(node->blocked);
ASSERT(node->blocker == this);
node->blocker.store(nullptr);
node->block_chain_prev = nullptr;
node->block_chain_next = nullptr;
Processor::scheduler().unblock_thread(node);
node = next;
}
m_block_chain = nullptr;
}
void ThreadBlocker::add_thread_to_block_queue(SchedulerThreadNode* node)
{
SpinLockGuard _(m_lock);
ASSERT(node->blocked);
ASSERT(node->blocker == nullptr);
node->blocker.store(this);
node->block_chain_prev = nullptr;
node->block_chain_next = m_block_chain;
if (m_block_chain)
m_block_chain->block_chain_prev = node;
m_block_chain = node;
}
void ThreadBlocker::remove_thread_from_block_queue(SchedulerThreadNode* node)
{
SpinLockGuard _(m_lock);
// NOTE: this is possible if we got here while another
// core was doing an unblock on this blocker
if (node->blocker.load() != this)
return;
ASSERT(node->blocked);
if (node->block_chain_prev)
node->block_chain_prev->block_chain_next = node->block_chain_next;
if (node->block_chain_next)
node->block_chain_next->block_chain_prev = node->block_chain_prev;
if (node == m_block_chain)
m_block_chain = node->block_chain_next;
node->blocker.store(nullptr);
node->block_chain_prev = nullptr;
node->block_chain_next = nullptr;
}
}