Kernel: Make TTY write lock a spinlock
I don't really like this but its needed with the current architecture to allow printing while interrupts are disabled. I was hitting a dead lock on few real machines
This commit is contained in:
@@ -100,9 +100,9 @@ namespace Kernel
|
||||
termios m_termios;
|
||||
|
||||
protected:
|
||||
Mutex m_mutex;
|
||||
Mutex m_input_mutex;
|
||||
|
||||
Mutex m_write_lock;
|
||||
RecursiveSpinLock m_write_lock;
|
||||
ThreadBlocker m_write_blocker;
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace Kernel
|
||||
|
||||
void clear() override;
|
||||
|
||||
BAN::ErrorOr<void> set_terminal_driver(BAN::RefPtr<TerminalDriver>);
|
||||
|
||||
protected:
|
||||
BAN::StringView name() const override { return m_name; }
|
||||
bool putchar_impl(uint8_t ch) override;
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Kernel
|
||||
auto slave = m_slave.lock();
|
||||
if (!slave)
|
||||
return BAN::Error::from_errno(EIO);
|
||||
LockGuard _(slave->m_mutex);
|
||||
LockGuard _(slave->m_input_mutex);
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
slave->handle_input_byte(buffer[i]);
|
||||
return buffer.size();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Input/InputDevice.h>
|
||||
#include <kernel/Lock/BlockableSpinLock.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
@@ -220,7 +221,7 @@ namespace Kernel
|
||||
if (ansi_c_str == nullptr)
|
||||
return;
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
LockGuard _(m_input_mutex);
|
||||
while (*ansi_c_str)
|
||||
handle_input_byte(*ansi_c_str++);
|
||||
after_write();
|
||||
@@ -269,7 +270,7 @@ namespace Kernel
|
||||
bool should_flush = false;
|
||||
bool force_echo = false;
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
LockGuard _(m_input_mutex);
|
||||
|
||||
if (!(termios.c_lflag & ICANON))
|
||||
should_flush = true;
|
||||
@@ -377,7 +378,8 @@ namespace Kernel
|
||||
|
||||
const auto termios = get_termios();
|
||||
|
||||
LockGuard _(m_write_lock);
|
||||
SpinLockGuard _(m_write_lock);
|
||||
|
||||
if (termios.c_oflag & OPOST)
|
||||
{
|
||||
if ((termios.c_oflag & ONLCR) && ch == NL)
|
||||
@@ -385,14 +387,16 @@ namespace Kernel
|
||||
if ((termios.c_oflag & OCRNL) && ch == CR)
|
||||
return putchar_impl(NL);
|
||||
}
|
||||
|
||||
return putchar_impl(ch);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
LockGuard _(m_input_mutex);
|
||||
|
||||
while (!m_output.flush)
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex));
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_input_mutex));
|
||||
|
||||
if (m_output.buffer->empty())
|
||||
{
|
||||
@@ -424,13 +428,14 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
LockGuard write_guard(m_write_lock);
|
||||
SpinLockGuard _(m_write_lock);
|
||||
|
||||
while (!can_write())
|
||||
{
|
||||
if (master_has_closed())
|
||||
return BAN::Error::from_errno(EIO);
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_write_blocker, &m_write_lock));
|
||||
BlockableSpinLock block(m_write_lock);
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_write_blocker, &block));
|
||||
}
|
||||
|
||||
size_t written = 0;
|
||||
@@ -447,15 +452,12 @@ namespace Kernel
|
||||
|
||||
void TTY::putchar_current(uint8_t ch)
|
||||
{
|
||||
ASSERT(s_tty);
|
||||
auto tty = s_tty;
|
||||
ASSERT(tty);
|
||||
|
||||
while (!s_tty->m_write_lock.try_lock())
|
||||
Processor::pause();
|
||||
|
||||
s_tty->putchar(ch);
|
||||
s_tty->after_write();
|
||||
|
||||
s_tty->m_write_lock.unlock();
|
||||
SpinLockGuard _(tty->m_write_lock);
|
||||
tty->putchar(ch);
|
||||
tty->after_write();
|
||||
}
|
||||
|
||||
bool TTY::is_initialized()
|
||||
|
||||
@@ -50,17 +50,48 @@ namespace Kernel
|
||||
, m_foreground(driver->palette()[15])
|
||||
, m_background(driver->palette()[0])
|
||||
{
|
||||
m_width = m_terminal_driver->width();
|
||||
m_height = m_terminal_driver->height();
|
||||
update_winsize(m_width, m_height);
|
||||
MUST(set_terminal_driver(driver));
|
||||
}
|
||||
|
||||
m_buffer = new Cell[m_width * m_height];
|
||||
ASSERT(m_buffer);
|
||||
BAN::ErrorOr<void> VirtualTTY::set_terminal_driver(BAN::RefPtr<TerminalDriver> terminal_driver)
|
||||
{
|
||||
const uint32_t new_width = terminal_driver->width();
|
||||
const uint32_t new_height = terminal_driver->height();
|
||||
|
||||
SpinLockGuard _(m_write_lock);
|
||||
|
||||
if (m_width != new_width || m_height != new_height)
|
||||
{
|
||||
Cell* new_buffer = new Cell[new_width * new_height];
|
||||
ASSERT(new_buffer);
|
||||
|
||||
for (uint32_t i = 0; i < new_width * m_height; i++)
|
||||
new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
||||
|
||||
for (uint32_t y = 0; y < BAN::Math::min<uint32_t>(m_height, new_height); y++)
|
||||
for (uint32_t x = 0; x < BAN::Math::min<uint32_t>(m_width, new_width); x++)
|
||||
new_buffer[y * new_width + x] = m_buffer[y * m_width + x];
|
||||
|
||||
delete[] m_buffer;
|
||||
m_buffer = new_buffer;
|
||||
m_width = new_width;
|
||||
m_height = new_height;
|
||||
}
|
||||
|
||||
m_terminal_driver = terminal_driver;
|
||||
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
render_from_buffer(x, y);
|
||||
|
||||
update_winsize(new_width, new_height);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void VirtualTTY::clear()
|
||||
{
|
||||
LockGuard _(m_write_lock);
|
||||
SpinLockGuard _(m_write_lock);
|
||||
for (uint32_t i = 0; i < m_width * m_height; i++)
|
||||
m_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
||||
m_terminal_driver->clear(m_background);
|
||||
@@ -70,46 +101,14 @@ namespace Kernel
|
||||
{
|
||||
if (!m_terminal_driver->has_font())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
{
|
||||
LockGuard _(m_write_lock);
|
||||
|
||||
TRY(m_terminal_driver->set_font(BAN::move(font)));
|
||||
|
||||
uint32_t new_width = m_terminal_driver->width();
|
||||
uint32_t new_height = m_terminal_driver->height();
|
||||
|
||||
if (m_width != new_width || m_height != new_height)
|
||||
{
|
||||
Cell* new_buffer = new Cell[new_width * new_height];
|
||||
ASSERT(new_buffer);
|
||||
|
||||
for (uint32_t i = 0; i < new_width * m_height; i++)
|
||||
new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
|
||||
|
||||
for (uint32_t y = 0; y < BAN::Math::min<uint32_t>(m_height, new_height); y++)
|
||||
for (uint32_t x = 0; x < BAN::Math::min<uint32_t>(m_width, new_width); x++)
|
||||
new_buffer[y * new_width + x] = m_buffer[y * m_width + x];
|
||||
|
||||
delete[] m_buffer;
|
||||
m_buffer = new_buffer;
|
||||
m_width = new_width;
|
||||
m_height = new_height;
|
||||
}
|
||||
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
render_from_buffer(x, y);
|
||||
}
|
||||
|
||||
update_winsize(m_width, m_height);
|
||||
|
||||
TRY(m_terminal_driver->set_font(BAN::move(font)));
|
||||
MUST(set_terminal_driver(m_terminal_driver));
|
||||
return {};
|
||||
}
|
||||
|
||||
void VirtualTTY::reset_ansi()
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
m_ansi_state = {
|
||||
.nums = { -1, -1, -1, -1, -1 },
|
||||
.index = 0,
|
||||
@@ -120,7 +119,7 @@ namespace Kernel
|
||||
|
||||
void VirtualTTY::handle_ansi_csi_color(uint8_t value)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
auto& palette = m_terminal_driver->palette();
|
||||
|
||||
@@ -203,7 +202,8 @@ namespace Kernel
|
||||
|
||||
void VirtualTTY::handle_ansi_csi(uint8_t ch)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '0' ... '9':
|
||||
@@ -445,7 +445,7 @@ namespace Kernel
|
||||
|
||||
void VirtualTTY::render_from_buffer(uint32_t x, uint32_t y)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
ASSERT(x < m_width && y < m_height);
|
||||
const auto& cell = m_buffer[y * m_width + x];
|
||||
m_terminal_driver->putchar_at(cell.codepoint, x, y, cell.foreground, cell.background);
|
||||
@@ -453,7 +453,7 @@ namespace Kernel
|
||||
|
||||
void VirtualTTY::putchar_at(uint32_t codepoint, uint32_t x, uint32_t y)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
ASSERT(x < m_width && y < m_height);
|
||||
auto& cell = m_buffer[y * m_width + x];
|
||||
cell.codepoint = codepoint;
|
||||
@@ -464,6 +464,8 @@ namespace Kernel
|
||||
|
||||
void VirtualTTY::scroll_if_needed()
|
||||
{
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
while (m_row >= m_height)
|
||||
{
|
||||
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
|
||||
@@ -487,7 +489,7 @@ namespace Kernel
|
||||
|
||||
void VirtualTTY::putcodepoint(uint32_t codepoint)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
switch (codepoint)
|
||||
{
|
||||
@@ -533,7 +535,7 @@ namespace Kernel
|
||||
|
||||
bool VirtualTTY::putchar_impl(uint8_t ch)
|
||||
{
|
||||
ASSERT(m_write_lock.is_locked_by_current_thread());
|
||||
ASSERT(m_write_lock.current_processor_has_lock());
|
||||
|
||||
uint32_t codepoint = ch;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user