Kernel: Semaphores and Threads can now be blocked with timeout

This commit is contained in:
Bananymous 2024-02-09 15:18:34 +02:00
parent 534b3e6a9a
commit ed0b1a86aa
17 changed files with 86 additions and 78 deletions

View File

@ -19,9 +19,9 @@ namespace Kernel
void reschedule(); void reschedule();
void reschedule_if_idling(); void reschedule_if_idling();
void set_current_thread_sleeping(uint64_t); void set_current_thread_sleeping(uint64_t wake_time);
void block_current_thread(Semaphore*); void block_current_thread(Semaphore*, uint64_t wake_time);
void unblock_threads(Semaphore*); void unblock_threads(Semaphore*);
// Makes sleeping or blocked thread with tid active. // Makes sleeping or blocked thread with tid active.
void unblock_thread(pid_t tid); void unblock_thread(pid_t tid);
@ -36,6 +36,8 @@ namespace Kernel
private: private:
Scheduler() = default; Scheduler() = default;
void set_current_thread_sleeping_impl(uint64_t wake_time);
void wake_threads(); void wake_threads();
[[nodiscard]] bool save_current_thread(); [[nodiscard]] bool save_current_thread();
void remove_and_advance_current_thread(); void remove_and_advance_current_thread();
@ -50,18 +52,14 @@ namespace Kernel
: thread(thread) : thread(thread)
{} {}
Thread* thread; Thread* thread;
union uint64_t wake_time;
{ Semaphore* semaphore;
uint64_t wake_time;
Semaphore* semaphore;
};
}; };
Thread* m_idle_thread { nullptr }; Thread* m_idle_thread { nullptr };
BAN::LinkedList<SchedulerThread> m_active_threads; BAN::LinkedList<SchedulerThread> m_active_threads;
BAN::LinkedList<SchedulerThread> m_sleeping_threads; BAN::LinkedList<SchedulerThread> m_sleeping_threads;
BAN::LinkedList<SchedulerThread> m_blocking_threads;
BAN::LinkedList<SchedulerThread>::iterator m_current_thread; BAN::LinkedList<SchedulerThread>::iterator m_current_thread;

View File

@ -6,7 +6,9 @@ namespace Kernel
class Semaphore class Semaphore
{ {
public: public:
void block(); void block_indefinite();
void block_with_timeout(uint64_t timeout_ms);
void block_with_wake_time(uint64_t wake_time_ms);
void unblock(); void unblock();
}; };

View File

@ -47,8 +47,10 @@ namespace Kernel
void handle_signal(int signal = 0); void handle_signal(int signal = 0);
bool add_signal(int signal); bool add_signal(int signal);
// blocks semaphore and returns either on unblock, eintr or spuriously // blocks semaphore and returns either on unblock, eintr, spuriously or after timeout
BAN::ErrorOr<void> block_or_eintr(Semaphore&); BAN::ErrorOr<void> block_or_eintr_indefinite(Semaphore& semaphore);
BAN::ErrorOr<void> block_or_eintr_or_timeout(Semaphore& semaphore, uint64_t timeout_ms, bool etimedout);
BAN::ErrorOr<void> block_or_eintr_or_waketime(Semaphore& semaphore, uint64_t wake_time_ms, bool etimedout);
void set_return_rsp(uintptr_t& rsp) { m_return_rsp = &rsp; } void set_return_rsp(uintptr_t& rsp) { m_return_rsp = &rsp; }
void set_return_rip(uintptr_t& rip) { m_return_rip = &rip; } void set_return_rip(uintptr_t& rip) { m_return_rip = &rip; }

View File

@ -64,9 +64,8 @@ namespace Kernel
{ {
while (!s_instance->m_should_sync) while (!s_instance->m_should_sync)
{ {
s_instance->m_device_lock.unlock(); LockFreeGuard _(s_instance->m_device_lock);
s_instance->m_sync_semaphore.block(); s_instance->m_sync_semaphore.block_indefinite();
s_instance->m_device_lock.lock();
} }
for (auto& device : s_instance->m_devices) for (auto& device : s_instance->m_devices)
@ -105,7 +104,7 @@ namespace Kernel
m_sync_semaphore.unblock(); m_sync_semaphore.unblock();
} }
if (should_block) if (should_block)
m_sync_done.block(); m_sync_done.block_indefinite();
} }
void DevFileSystem::add_device(BAN::RefPtr<Device> device) void DevFileSystem::add_device(BAN::RefPtr<Device> device)

View File

@ -1,5 +1,6 @@
#include <kernel/FS/Pipe.h> #include <kernel/FS/Pipe.h>
#include <kernel/LockGuard.h> #include <kernel/LockGuard.h>
#include <kernel/Thread.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
namespace Kernel namespace Kernel
@ -46,9 +47,8 @@ namespace Kernel
{ {
if (m_writing_count == 0) if (m_writing_count == 0)
return 0; return 0;
m_lock.unlock(); LockFreeGuard lock_free(m_lock);
m_semaphore.block(); TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
m_lock.lock();
} }
size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer.size()); size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer.size());

View File

@ -195,7 +195,7 @@ namespace Kernel::Input
while (true) while (true)
{ {
if (m_event_queue.empty()) if (m_event_queue.empty())
TRY(Thread::current().block_or_eintr(m_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
CriticalScope _; CriticalScope _;
if (m_event_queue.empty()) if (m_event_queue.empty())

View File

@ -179,7 +179,7 @@ namespace Kernel::Input
while (true) while (true)
{ {
if (m_event_queue.empty()) if (m_event_queue.empty())
TRY(Thread::current().block_or_eintr(m_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
CriticalScope _; CriticalScope _;
if (m_event_queue.empty()) if (m_event_queue.empty())

View File

@ -155,7 +155,7 @@ namespace Kernel
if (!pending.has_value()) if (!pending.has_value())
{ {
m_pending_semaphore.block(); m_pending_semaphore.block_indefinite();
continue; continue;
} }

View File

@ -239,7 +239,7 @@ namespace Kernel
if (!pending.has_value()) if (!pending.has_value())
{ {
m_pending_semaphore.block(); m_pending_semaphore.block_indefinite();
continue; continue;
} }

View File

@ -65,7 +65,7 @@ namespace Kernel
BAN::ErrorOr<size_t> UDPSocket::read_packet(BAN::ByteSpan buffer, sockaddr_in* sender_addr) BAN::ErrorOr<size_t> UDPSocket::read_packet(BAN::ByteSpan buffer, sockaddr_in* sender_addr)
{ {
while (m_packets.empty()) while (m_packets.empty())
TRY(Thread::current().block_or_eintr(m_packet_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_semaphore));
LockGuard _(m_packet_lock); LockGuard _(m_packet_lock);
if (m_packets.empty()) if (m_packets.empty())

View File

@ -66,7 +66,7 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
while (connection_info.pending_connections.empty()) while (connection_info.pending_connections.empty())
TRY(Thread::current().block_or_eintr(connection_info.pending_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_semaphore));
BAN::RefPtr<UnixDomainSocket> pending; BAN::RefPtr<UnixDomainSocket> pending;
@ -158,7 +158,7 @@ namespace Kernel
break; break;
} }
} }
TRY(Thread::current().block_or_eintr(target_info.pending_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(target_info.pending_semaphore));
} }
while (!connection_info.connection_done) while (!connection_info.connection_done)
@ -234,7 +234,7 @@ namespace Kernel
while (m_packet_sizes.full() || m_packet_size_total + packet.size() > s_packet_buffer_size) while (m_packet_sizes.full() || m_packet_size_total + packet.size() > s_packet_buffer_size)
{ {
LockFreeGuard _(m_lock); LockFreeGuard _(m_lock);
TRY(Thread::current().block_or_eintr(m_packet_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_semaphore));
} }
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr() + m_packet_size_total); uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr() + m_packet_size_total);
@ -321,7 +321,7 @@ namespace Kernel
while (m_packet_size_total == 0) while (m_packet_size_total == 0)
{ {
LockFreeGuard _(m_lock); LockFreeGuard _(m_lock);
TRY(Thread::current().block_or_eintr(m_packet_semaphore)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_semaphore));
} }
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr()); uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr());

View File

@ -568,7 +568,7 @@ namespace Kernel
return BAN::Error::from_errno(ECHILD); return BAN::Error::from_errno(ECHILD);
while (!target->m_exit_status.exited) while (!target->m_exit_status.exited)
TRY(Thread::current().block_or_eintr(target->m_exit_status.semaphore)); TRY(Thread::current().block_or_eintr_indefinite(target->m_exit_status.semaphore));
int exit_status = target->m_exit_status.exit_code; int exit_status = target->m_exit_status.exit_code;
target->m_exit_status.waiting--; target->m_exit_status.waiting--;

View File

@ -278,12 +278,9 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
void Scheduler::set_current_thread_sleeping(uint64_t wake_time) void Scheduler::set_current_thread_sleeping_impl(uint64_t wake_time)
{ {
VERIFY_STI(); VERIFY_CLI();
DISABLE_INTERRUPTS();
ASSERT(m_current_thread);
if (save_current_thread()) if (save_current_thread())
{ {
@ -310,42 +307,37 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
void Scheduler::block_current_thread(Semaphore* semaphore) void Scheduler::set_current_thread_sleeping(uint64_t wake_time)
{ {
VERIFY_STI(); VERIFY_STI();
DISABLE_INTERRUPTS(); DISABLE_INTERRUPTS();
ASSERT(m_current_thread); ASSERT(m_current_thread);
if (save_current_thread()) m_current_thread->semaphore = nullptr;
{ set_current_thread_sleeping_impl(wake_time);
ENABLE_INTERRUPTS(); }
return;
} void Scheduler::block_current_thread(Semaphore* semaphore, uint64_t wake_time)
{
VERIFY_STI();
DISABLE_INTERRUPTS();
ASSERT(m_current_thread);
m_current_thread->semaphore = semaphore; m_current_thread->semaphore = semaphore;
m_active_threads.move_element_to_other_linked_list( set_current_thread_sleeping_impl(wake_time);
m_blocking_threads,
m_blocking_threads.end(),
m_current_thread
);
m_current_thread = {};
advance_current_thread();
execute_current_thread();
ASSERT_NOT_REACHED();
} }
void Scheduler::unblock_threads(Semaphore* semaphore) void Scheduler::unblock_threads(Semaphore* semaphore)
{ {
CriticalScope critical; CriticalScope critical;
for (auto it = m_blocking_threads.begin(); it != m_blocking_threads.end();) for (auto it = m_sleeping_threads.begin(); it != m_sleeping_threads.end();)
{ {
if (it->semaphore == semaphore) if (it->semaphore == semaphore)
{ {
it = m_blocking_threads.move_element_to_other_linked_list( it = m_sleeping_threads.move_element_to_other_linked_list(
m_active_threads, m_active_threads,
m_active_threads.end(), m_active_threads.end(),
it it
@ -362,19 +354,6 @@ namespace Kernel
{ {
CriticalScope _; CriticalScope _;
for (auto it = m_blocking_threads.begin(); it != m_blocking_threads.end(); it++)
{
if (it->thread->tid() == tid)
{
m_blocking_threads.move_element_to_other_linked_list(
m_active_threads,
m_active_threads.end(),
it
);
return;
}
}
for (auto it = m_sleeping_threads.begin(); it != m_sleeping_threads.end(); it++) for (auto it = m_sleeping_threads.begin(); it != m_sleeping_threads.end(); it++)
{ {
if (it->thread->tid() == tid) if (it->thread->tid() == tid)

View File

@ -1,12 +1,23 @@
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Semaphore.h> #include <kernel/Semaphore.h>
#include <kernel/Timer/Timer.h>
namespace Kernel namespace Kernel
{ {
void Semaphore::block() void Semaphore::block_indefinite()
{ {
Scheduler::get().block_current_thread(this); Scheduler::get().block_current_thread(this, ~(uint64_t)0);
}
void Semaphore::block_with_timeout(uint64_t timeout_ms)
{
Scheduler::get().block_current_thread(this, SystemTimer::get().ms_since_boot() + timeout_ms);
}
void Semaphore::block_with_wake_time(uint64_t wake_time)
{
Scheduler::get().block_current_thread(this, wake_time);
} }
void Semaphore::unblock() void Semaphore::unblock()

View File

@ -67,13 +67,12 @@ namespace Kernel
while (SystemTimer::get().ms_since_boot() < start_time + s_nvme_command_timeout_ms) while (SystemTimer::get().ms_since_boot() < start_time + s_nvme_command_timeout_ms)
{ {
if (!m_done) if (m_done)
{ {
m_semaphore.block(); m_done = false;
continue; return m_status;
} }
m_done = false; m_semaphore.block_with_wake_time(start_time + s_nvme_command_timeout_ms);
return m_status;
} }
return 0xFFFF; return 0xFFFF;

View File

@ -92,7 +92,7 @@ namespace Kernel
while (true) while (true)
{ {
while (!TTY::current()->m_tty_ctrl.receive_input) while (!TTY::current()->m_tty_ctrl.receive_input)
TTY::current()->m_tty_ctrl.semaphore.block(); TTY::current()->m_tty_ctrl.semaphore.block_indefinite();
Input::KeyEvent event; Input::KeyEvent event;
size_t read = MUST(inode->read(0, BAN::ByteSpan::from(event))); size_t read = MUST(inode->read(0, BAN::ByteSpan::from(event)));
@ -323,7 +323,7 @@ namespace Kernel
uint32_t depth = m_lock.lock_depth(); uint32_t depth = m_lock.lock_depth();
for (uint32_t i = 0; i < depth; i++) for (uint32_t i = 0; i < depth; i++)
m_lock.unlock(); m_lock.unlock();
auto eintr = Thread::current().block_or_eintr(m_output.semaphore); auto eintr = Thread::current().block_or_eintr_indefinite(m_output.semaphore);
for (uint32_t i = 0; i < depth; i++) for (uint32_t i = 0; i < depth; i++)
m_lock.lock(); m_lock.lock();
if (eintr.is_error()) if (eintr.is_error())

View File

@ -8,6 +8,7 @@
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
#include <kernel/Timer/Timer.h>
namespace Kernel namespace Kernel
{ {
@ -30,7 +31,6 @@ namespace Kernel
void Thread::terminate() void Thread::terminate()
{ {
CriticalScope _; CriticalScope _;
ASSERT(this == &Thread::current());
m_state = Thread::State::Terminated; m_state = Thread::State::Terminated;
if (this == &Thread::current()) if (this == &Thread::current())
Scheduler::get().execute_current_thread(); Scheduler::get().execute_current_thread();
@ -343,16 +343,34 @@ namespace Kernel
return false; return false;
} }
BAN::ErrorOr<void> Thread::block_or_eintr(Semaphore& semaphore) BAN::ErrorOr<void> Thread::block_or_eintr_indefinite(Semaphore& semaphore)
{ {
if (is_interrupted_by_signal()) if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
semaphore.block(); semaphore.block_indefinite();
if (is_interrupted_by_signal()) if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
return {}; return {};
} }
BAN::ErrorOr<void> Thread::block_or_eintr_or_timeout(Semaphore& semaphore, uint64_t timeout_ms, bool etimedout)
{
uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + timeout_ms;
return block_or_eintr_or_waketime(semaphore, wake_time_ms, etimedout);
}
BAN::ErrorOr<void> Thread::block_or_eintr_or_waketime(Semaphore& semaphore, uint64_t wake_time_ms, bool etimedout)
{
if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR);
semaphore.block_with_wake_time(wake_time_ms);
if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR);
if (etimedout && SystemTimer::get().ms_since_boot() >= wake_time_ms)
return BAN::Error::from_errno(ETIMEDOUT);
return {};
}
void Thread::validate_stack() const void Thread::validate_stack() const
{ {
if (stack_base() <= m_rsp && m_rsp <= stack_base() + stack_size()) if (stack_base() <= m_rsp && m_rsp <= stack_base() + stack_size())