Kernel: Replace CriticalScopes with SpinLock in PS/2 and input code

This commit is contained in:
Bananymous 2024-02-29 11:41:57 +02:00
parent ec0cb5fd54
commit 7f028f70d5
8 changed files with 58 additions and 53 deletions

View File

@ -3,6 +3,7 @@
#include <BAN/Array.h>
#include <BAN/UniqPtr.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Lock/SpinLock.h>
namespace Kernel::Input
{
@ -23,6 +24,7 @@ namespace Kernel::Input
BAN::Array<Key, 0xFF> m_keycode_to_key_normal;
BAN::Array<Key, 0xFF> m_keycode_to_key_shift;
BAN::Array<Key, 0xFF> m_keycode_to_key_altgr;
SpinLock m_lock;
friend class BAN::UniqPtr<KeyboardLayout>;
};

View File

@ -64,6 +64,7 @@ namespace Kernel::Input
BAN::CircularQueue<Command, 128> m_command_queue;
uint64_t m_command_send_time { 0 };
SpinLock m_command_lock;
};
}

View File

@ -41,6 +41,7 @@ namespace Kernel::Input
uint16_t m_modifiers { 0 };
BAN::CircularQueue<KeyEvent, 50> m_event_queue;
SpinLock m_event_lock;
PS2Keymap m_keymap;

View File

@ -37,6 +37,7 @@ namespace Kernel::Input
uint8_t m_button_mask { 0x00 };
BAN::CircularQueue<MouseEvent, 128> m_event_queue;
SpinLock m_event_lock;
Semaphore m_semaphore;

View File

@ -1,5 +1,4 @@
#include <BAN/HashMap.h>
#include <kernel/CriticalScope.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Input/KeyboardLayout.h>
@ -74,6 +73,7 @@ namespace Kernel::Input
Key KeyboardLayout::get_key_from_event(KeyEvent event)
{
SpinLockGuard _(m_lock);
if (event.shift())
return m_keycode_to_key_shift[event.keycode];
if (event.ralt())
@ -256,7 +256,7 @@ namespace Kernel::Input
}
}
CriticalScope _;
SpinLockGuard _(m_lock);
for (size_t i = 0; i < new_layout->m_keycode_to_key_normal.size(); i++)
if (new_layout->m_keycode_to_key_normal[i] != Key::None)

View File

@ -6,7 +6,6 @@
#include <kernel/Input/PS2/Controller.h>
#include <kernel/Input/PS2/Keyboard.h>
#include <kernel/Input/PS2/Mouse.h>
#include <kernel/InterruptController.h>
#include <kernel/IO.h>
#include <kernel/Timer/Timer.h>
@ -21,7 +20,6 @@ namespace Kernel::Input
BAN::ErrorOr<void> PS2Controller::send_byte(uint16_t port, uint8_t byte)
{
ASSERT(interrupts_enabled());
LockGuard _(m_mutex);
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
while (SystemTimer::get().ms_since_boot() < timeout)
@ -36,7 +34,6 @@ namespace Kernel::Input
BAN::ErrorOr<uint8_t> PS2Controller::read_byte()
{
ASSERT(interrupts_enabled());
LockGuard _(m_mutex);
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
while (SystemTimer::get().ms_since_boot() < timeout)
@ -101,8 +98,7 @@ namespace Kernel::Input
bool PS2Controller::append_command_queue(PS2Device* device, uint8_t command, uint8_t response_size)
{
// NOTE: command queue push/pop must be done without interrupts
CriticalScope _;
SpinLockGuard _(m_command_lock);
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
{
dprintln("PS/2 command queue full");
@ -121,8 +117,7 @@ namespace Kernel::Input
bool PS2Controller::append_command_queue(PS2Device* device, uint8_t command, uint8_t data, uint8_t response_size)
{
// NOTE: command queue push/pop must be done without interrupts
CriticalScope _;
SpinLockGuard _(m_command_lock);
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
{
dprintln("PS/2 command queue full");
@ -141,35 +136,38 @@ namespace Kernel::Input
void PS2Controller::update_command_queue()
{
ASSERT(interrupts_enabled());
Command command_copy;
if (m_command_queue.empty())
return;
auto& command = m_command_queue.front();
if (command.state == Command::State::WaitingResponse || command.state == Command::State::WaitingAck)
{
if (SystemTimer::get().ms_since_boot() >= m_command_send_time + s_ps2_timeout_ms)
SpinLockGuard _(m_command_lock);
if (m_command_queue.empty())
return;
auto& command = m_command_queue.front();
if (command.state == Command::State::WaitingResponse || command.state == Command::State::WaitingAck)
{
dwarnln_if(DEBUG_PS2, "Command timedout");
m_devices[command.device_index]->command_timedout(command.out_data, command.out_count);
m_command_queue.pop();
if (SystemTimer::get().ms_since_boot() >= m_command_send_time + s_ps2_timeout_ms)
{
dwarnln_if(DEBUG_PS2, "Command timedout");
m_devices[command.device_index]->command_timedout(command.out_data, command.out_count);
m_command_queue.pop();
}
return;
}
return;
ASSERT(command.send_index < command.out_count);
command.state = Command::State::WaitingAck;
command_copy = command;
}
ASSERT(command.send_index < command.out_count);
command.state = Command::State::WaitingAck;
m_command_send_time = SystemTimer::get().ms_since_boot();
if (auto ret = device_send_byte(command.device_index, command.out_data[command.send_index]); ret.is_error())
{
command.state = Command::State::Sending;
if (auto ret = device_send_byte(command_copy.device_index, command_copy.out_data[command_copy.send_index]); ret.is_error())
dwarnln_if(DEBUG_PS2, "PS/2 send command byte: {}", ret.error());
}
}
bool PS2Controller::handle_command_byte(PS2Device* device, uint8_t byte)
{
// NOTE: command queue push/pop must be done without interrupts
ASSERT(!interrupts_enabled());
SpinLockGuard _(m_command_lock);
if (m_command_queue.empty())
return false;

View File

@ -1,5 +1,4 @@
#include <BAN/ScopeGuard.h>
#include <kernel/CriticalScope.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/KeyboardLayout.h>
#include <kernel/Input/PS2/Config.h>
@ -165,6 +164,8 @@ namespace Kernel::Input
event.modifier = m_modifiers | (released ? 0 : KeyEvent::Modifier::Pressed);
event.keycode = keycode.value();
SpinLockGuard _(m_event_lock);
if (m_event_queue.full())
{
dwarnln("PS/2 event queue full");
@ -192,20 +193,20 @@ namespace Kernel::Input
if (buffer.size() < sizeof(KeyEvent))
return BAN::Error::from_errno(ENOBUFS);
while (true)
auto state = m_event_lock.lock();
while (m_event_queue.empty())
{
if (m_event_queue.empty())
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
CriticalScope _;
if (m_event_queue.empty())
continue;
buffer.as<KeyEvent>() = m_event_queue.front();
m_event_queue.pop();
return sizeof(KeyEvent);
m_event_lock.unlock(state);
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
state = m_event_lock.lock();
}
buffer.as<KeyEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(KeyEvent);
}
}

View File

@ -1,5 +1,4 @@
#include <BAN/ScopeGuard.h>
#include <kernel/CriticalScope.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Mouse.h>
@ -158,6 +157,8 @@ namespace Kernel::Input
event.scroll_event.scroll = rel_z;
}
SpinLockGuard _(m_event_lock);
for (int i = 0; i < event_count; i++)
{
if (m_event_queue.full())
@ -176,20 +177,20 @@ namespace Kernel::Input
if (buffer.size() < sizeof(MouseEvent))
return BAN::Error::from_errno(ENOBUFS);
while (true)
auto state = m_event_lock.lock();
while (m_event_queue.empty())
{
if (m_event_queue.empty())
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
CriticalScope _;
if (m_event_queue.empty())
continue;
buffer.as<MouseEvent>() = m_event_queue.front();
m_event_queue.pop();
return sizeof(MouseEvent);
m_event_lock.unlock(state);
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
state = m_event_lock.lock();
}
buffer.as<MouseEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(MouseEvent);
}
}