forked from Bananymous/banan-os
Kernel: Add Semaphore to block threads
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
20
kernel/kernel/Semaphore.cpp
Normal file
20
kernel/kernel/Semaphore.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user