Kernel: Add Semaphore to block threads
This commit is contained in:
parent
c32584cca0
commit
c8f05b4a7a
|
@ -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 \
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue