From c2e3b422ccbf1461e88132da4276e8f0468a4bd2 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 30 Mar 2023 18:45:47 +0300 Subject: [PATCH] Kernel: Add Semaphore to block threads --- kernel/Makefile | 1 + kernel/include/kernel/Input/PS2Keyboard.h | 3 ++ kernel/include/kernel/Scheduler.h | 13 ++++++ kernel/include/kernel/Semaphore.h | 24 ++++++++++ kernel/kernel/Input/PS2Keyboard.cpp | 21 ++++++--- kernel/kernel/Scheduler.cpp | 54 +++++++++++++++++++++++ kernel/kernel/Semaphore.cpp | 20 +++++++++ 7 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 kernel/include/kernel/Semaphore.h create mode 100644 kernel/kernel/Semaphore.cpp diff --git a/kernel/Makefile b/kernel/Makefile index 762715b36e..e3e1af8f53 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -57,6 +57,7 @@ kernel/PIT.o \ kernel/Process.o \ kernel/RTC.o \ kernel/Scheduler.o \ +kernel/Semaphore.o \ kernel/Serial.o \ kernel/Shell.o \ kernel/SpinLock.o \ diff --git a/kernel/include/kernel/Input/PS2Keyboard.h b/kernel/include/kernel/Input/PS2Keyboard.h index 9d2ce9cec1..f28226e4d8 100644 --- a/kernel/include/kernel/Input/PS2Keyboard.h +++ b/kernel/include/kernel/Input/PS2Keyboard.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Kernel::Input { @@ -60,6 +61,8 @@ namespace Kernel::Input State m_state { State::Normal }; + Semaphore m_semaphore; + BAN::String m_name; public: diff --git a/kernel/include/kernel/Scheduler.h b/kernel/include/kernel/Scheduler.h index f0ee003c1b..655c78187d 100644 --- a/kernel/include/kernel/Scheduler.h +++ b/kernel/include/kernel/Scheduler.h @@ -2,6 +2,7 @@ #include #include +#include #include namespace Kernel @@ -21,6 +22,9 @@ namespace Kernel void set_current_thread_sleeping(uint64_t); [[noreturn]] void set_current_thread_done(); + void block_current_thread(Semaphore*); + void unblock_threads(Semaphore*); + BAN::RefPtr current_thread(); private: @@ -47,9 +51,18 @@ namespace Kernel uint64_t wake_time; }; + struct BlockingThread + { + BlockingThread(const BAN::RefPtr& thread, Semaphore* semaphore) : thread(thread), semaphore(semaphore) {} + BAN::RefPtr thread; + Semaphore* semaphore; + uint8_t padding[sizeof(uint64_t) - sizeof(Semaphore*)]; + }; + BAN::RefPtr m_idle_thread; BAN::LinkedList m_active_threads; BAN::LinkedList m_sleeping_threads; + BAN::LinkedList m_blocking_threads; BAN::LinkedList::iterator m_current_thread; diff --git a/kernel/include/kernel/Semaphore.h b/kernel/include/kernel/Semaphore.h new file mode 100644 index 0000000000..4b85f31c3f --- /dev/null +++ b/kernel/include/kernel/Semaphore.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace Kernel +{ + + class Semaphore + { + public: + void block(); + void unblock(); + bool is_blocked() const { return m_blocked; } + + private: + void set_blocked(bool blocked) { m_blocked = blocked; } + + private: + bool m_blocked { false }; + + friend class Scheduler; + }; + +} \ No newline at end of file diff --git a/kernel/kernel/Input/PS2Keyboard.cpp b/kernel/kernel/Input/PS2Keyboard.cpp index 6e44e7bc81..ec775629d9 100644 --- a/kernel/kernel/Input/PS2Keyboard.cpp +++ b/kernel/kernel/Input/PS2Keyboard.cpp @@ -211,8 +211,9 @@ namespace Kernel::Input m_event_queue.pop(); } m_event_queue.push(event); - } + m_semaphore.unblock(); + } void PS2Keyboard::update_leds() { @@ -231,14 +232,20 @@ namespace Kernel::Input if (size < sizeof(KeyEvent)) return BAN::Error::from_errno(ENOBUFS); - while (m_event_queue.empty()) - PIT::sleep(1); + while (true) + { + if (m_event_queue.empty()) + m_semaphore.block(); - CriticalScope _; - *(KeyEvent*)buffer = m_event_queue.front(); - m_event_queue.pop(); + CriticalScope _; + if (m_event_queue.empty()) + continue; - return sizeof(KeyEvent); + *(KeyEvent*)buffer = m_event_queue.front(); + m_event_queue.pop(); + + return sizeof(KeyEvent); + } } } \ No newline at end of file diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 522b9b5afd..7686e3dfd7 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -211,4 +211,58 @@ namespace Kernel ASSERT_NOT_REACHED(); } +#pragma GCC push_options +#pragma GCC optimize("O0") + void Scheduler::block_current_thread(Semaphore* semaphore) + { + VERIFY_STI(); + DISABLE_INTERRUPTS(); + + ASSERT(m_current_thread); + + auto blocking = m_current_thread->thread; + + if (save_current_thread()) + { + ENABLE_INTERRUPTS(); + return; + } + remove_and_advance_current_thread(); + + // This should work as we released enough memory from active thread + static_assert(sizeof(ActiveThread) == sizeof(BlockingThread)); + MUST(m_blocking_threads.emplace_back(blocking, semaphore)); + blocking.clear(); + + semaphore->m_blocked = true; + + execute_current_thread(); + ASSERT_NOT_REACHED(); + } +#pragma GCC pop_options + + void Scheduler::unblock_threads(Semaphore* semaphore) + { + Kernel::CriticalScope critical; + + for (auto it = m_blocking_threads.begin(); it != m_blocking_threads.end();) + { + if (it->semaphore == semaphore) + { + auto thread = it->thread; + it = m_blocking_threads.remove(it); + + // This should work as we released enough memory from active thread + static_assert(sizeof(ActiveThread) == sizeof(BlockingThread)); + MUST(m_active_threads.emplace_back(thread)); + } + else + { + it++; + } + } + + semaphore->m_blocked = false; + } + } \ No newline at end of file diff --git a/kernel/kernel/Semaphore.cpp b/kernel/kernel/Semaphore.cpp new file mode 100644 index 0000000000..30076a53e9 --- /dev/null +++ b/kernel/kernel/Semaphore.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +namespace Kernel +{ + + void Semaphore::block() + { + Scheduler::get().block_current_thread(this); + } + + void Semaphore::unblock() + { + if (!m_blocked) + return; + Scheduler::get().unblock_threads(this); + } + +} \ No newline at end of file