Kernel: Add Semaphore to block threads

This commit is contained in:
Bananymous 2023-03-30 18:45:47 +03:00
parent c32584cca0
commit c8f05b4a7a
7 changed files with 129 additions and 7 deletions

View File

@ -57,6 +57,7 @@ kernel/PIT.o \
kernel/Process.o \ kernel/Process.o \
kernel/RTC.o \ kernel/RTC.o \
kernel/Scheduler.o \ kernel/Scheduler.o \
kernel/Semaphore.o \
kernel/Serial.o \ kernel/Serial.o \
kernel/Shell.o \ kernel/Shell.o \
kernel/SpinLock.o \ kernel/SpinLock.o \

View File

@ -4,6 +4,7 @@
#include <kernel/Input/KeyEvent.h> #include <kernel/Input/KeyEvent.h>
#include <kernel/Input/PS2Controller.h> #include <kernel/Input/PS2Controller.h>
#include <kernel/Input/PS2Keymap.h> #include <kernel/Input/PS2Keymap.h>
#include <kernel/Semaphore.h>
namespace Kernel::Input namespace Kernel::Input
{ {
@ -60,6 +61,8 @@ namespace Kernel::Input
State m_state { State::Normal }; State m_state { State::Normal };
Semaphore m_semaphore;
BAN::String m_name; BAN::String m_name;
public: public:

View File

@ -2,6 +2,7 @@
#include <BAN/LinkedList.h> #include <BAN/LinkedList.h>
#include <BAN/Memory.h> #include <BAN/Memory.h>
#include <kernel/Semaphore.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
namespace Kernel namespace Kernel
@ -21,6 +22,9 @@ namespace Kernel
void set_current_thread_sleeping(uint64_t); void set_current_thread_sleeping(uint64_t);
[[noreturn]] void set_current_thread_done(); [[noreturn]] void set_current_thread_done();
void block_current_thread(Semaphore*);
void unblock_threads(Semaphore*);
BAN::RefPtr<Thread> current_thread(); BAN::RefPtr<Thread> current_thread();
private: private:
@ -47,9 +51,18 @@ namespace Kernel
uint64_t wake_time; uint64_t wake_time;
}; };
struct BlockingThread
{
BlockingThread(const BAN::RefPtr<Thread>& thread, Semaphore* semaphore) : thread(thread), semaphore(semaphore) {}
BAN::RefPtr<Thread> thread;
Semaphore* semaphore;
uint8_t padding[sizeof(uint64_t) - sizeof(Semaphore*)];
};
BAN::RefPtr<Thread> m_idle_thread; BAN::RefPtr<Thread> m_idle_thread;
BAN::LinkedList<ActiveThread> m_active_threads; BAN::LinkedList<ActiveThread> m_active_threads;
BAN::LinkedList<SleepingThread> m_sleeping_threads; BAN::LinkedList<SleepingThread> m_sleeping_threads;
BAN::LinkedList<BlockingThread> m_blocking_threads;
BAN::LinkedList<ActiveThread>::iterator m_current_thread; BAN::LinkedList<ActiveThread>::iterator m_current_thread;

View File

@ -0,0 +1,24 @@
#pragma once
#include <kernel/SpinLock.h>
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;
};
}

View File

@ -211,8 +211,9 @@ namespace Kernel::Input
m_event_queue.pop(); m_event_queue.pop();
} }
m_event_queue.push(event); m_event_queue.push(event);
}
m_semaphore.unblock();
}
void PS2Keyboard::update_leds() void PS2Keyboard::update_leds()
{ {
@ -231,14 +232,20 @@ namespace Kernel::Input
if (size < sizeof(KeyEvent)) if (size < sizeof(KeyEvent))
return BAN::Error::from_errno(ENOBUFS); return BAN::Error::from_errno(ENOBUFS);
while (m_event_queue.empty()) while (true)
PIT::sleep(1); {
if (m_event_queue.empty())
m_semaphore.block();
CriticalScope _; CriticalScope _;
*(KeyEvent*)buffer = m_event_queue.front(); if (m_event_queue.empty())
m_event_queue.pop(); continue;
return sizeof(KeyEvent); *(KeyEvent*)buffer = m_event_queue.front();
m_event_queue.pop();
return sizeof(KeyEvent);
}
} }
} }

View File

@ -211,4 +211,58 @@ namespace Kernel
ASSERT_NOT_REACHED(); 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;
}
} }

View File

@ -0,0 +1,20 @@
#include <kernel/LockGuard.h>
#include <kernel/Scheduler.h>
#include <kernel/Semaphore.h>
namespace Kernel
{
void Semaphore::block()
{
Scheduler::get().block_current_thread(this);
}
void Semaphore::unblock()
{
if (!m_blocked)
return;
Scheduler::get().unblock_threads(this);
}
}