Kernel: Make tty use the new byte ring buffer

This commit is contained in:
Bananymous 2026-02-28 14:53:15 +02:00
parent a602753bda
commit eeef945c25
2 changed files with 50 additions and 63 deletions

View File

@ -3,6 +3,7 @@
#include <BAN/Array.h> #include <BAN/Array.h>
#include <kernel/Device/Device.h> #include <kernel/Device/Device.h>
#include <kernel/Lock/SpinLock.h> #include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/Terminal/TerminalDriver.h> #include <kernel/Terminal/TerminalDriver.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
#include <LibInput/KeyEvent.h> #include <LibInput/KeyEvent.h>
@ -102,8 +103,7 @@ namespace Kernel
struct Buffer struct Buffer
{ {
BAN::Array<uint8_t, 1024> buffer; BAN::UniqPtr<ByteRingBuffer> buffer;
size_t bytes { 0 };
bool flush { false }; bool flush { false };
ThreadBlocker thread_blocker; ThreadBlocker thread_blocker;
}; };

View File

@ -73,7 +73,9 @@ namespace Kernel
: CharacterDevice(mode, uid, gid) : CharacterDevice(mode, uid, gid)
, m_termios(termios) , m_termios(termios)
, m_rdev(next_tty_rdev()) , m_rdev(next_tty_rdev())
{ } {
m_output.buffer = MUST(ByteRingBuffer::create(PAGE_SIZE));
}
BAN::RefPtr<TTY> TTY::current() BAN::RefPtr<TTY> TTY::current()
{ {
@ -204,7 +206,7 @@ namespace Kernel
} }
case FIONREAD: case FIONREAD:
{ {
*static_cast<int*>(argument) = m_output.flush ? m_output.bytes : 0; *static_cast<int*>(argument) = m_output.flush ? m_output.buffer->size() : 0;
return 0; return 0;
} }
case TIOCGWINSZ: case TIOCGWINSZ:
@ -232,13 +234,12 @@ namespace Kernel
return; return;
const char* ansi_c_str = LibInput::key_to_utf8_ansi(event.key, event.modifier); const char* ansi_c_str = LibInput::key_to_utf8_ansi(event.key, event.modifier);
if (ansi_c_str) if (ansi_c_str == nullptr)
{ return;
auto* ptr = reinterpret_cast<const uint8_t*>(ansi_c_str);
while (*ptr) while (*ansi_c_str)
handle_input_byte(*ptr++); handle_input_byte(*ansi_c_str++);
after_write(); after_write();
}
} }
void TTY::handle_input_byte(uint8_t ch) void TTY::handle_input_byte(uint8_t ch)
@ -287,7 +288,7 @@ namespace Kernel
if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK)) if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK))
{ {
while (m_output.bytes > 0 && m_output.buffer[m_output.bytes - 1] != '\n') while (!m_output.buffer->empty() && m_output.buffer->back() != '\n')
do_backspace(); do_backspace();
return; return;
} }
@ -307,12 +308,8 @@ namespace Kernel
// TODO: terminal suspension with VSTOP/VSTART // TODO: terminal suspension with VSTOP/VSTART
if (should_append) if (should_append && !m_output.buffer->full())
{ m_output.buffer->push({ &ch, 1 });
if (m_output.bytes >= m_output.buffer.size())
return;
m_output.buffer[m_output.bytes++] = ch;
}
if (should_append && (force_echo || (m_termios.c_lflag & ECHO))) if (should_append && (force_echo || (m_termios.c_lflag & ECHO)))
{ {
@ -350,44 +347,34 @@ namespace Kernel
void TTY::do_backspace() void TTY::do_backspace()
{ {
if (m_output.bytes > 0) if (m_output.buffer->empty())
{ return;
uint8_t last = m_output.buffer[m_output.bytes - 1];
// Multibyte UTF8 const bool is_caret_notation =
if ((last & 0xC0) == 0x80) (m_output.buffer->back() < 32) ||
{ (m_output.buffer->back() == 127);
// NOTE: this should be valid UTF8 since keyboard input already 'validates' it
while ((m_output.buffer[m_output.bytes - 1] & 0xC0) == 0x80) // handle multibyte UTF8
{ while ((m_output.buffer->back() & 0xC0) == 0x80)
ASSERT(m_output.bytes > 0); m_output.buffer->pop_back(1);
m_output.bytes--;
} ASSERT(!m_output.buffer->empty());
ASSERT(m_output.bytes > 0); m_output.buffer->pop_back(1);
m_output.bytes--;
putchar('\b'); if (is_caret_notation)
putchar(' '); {
putchar('\b'); putchar('\b');
} putchar('\b');
// Caret notation putchar(' ');
else if (last < 32 || last == 127) putchar(' ');
{ putchar('\b');
m_output.bytes--; putchar('\b');
putchar('\b'); }
putchar('\b'); else
putchar(' '); {
putchar(' '); putchar('\b');
putchar('\b'); putchar(' ');
putchar('\b'); putchar('\b');
}
// Ascii
else
{
m_output.bytes--;
putchar('\b');
putchar(' ');
putchar('\b');
}
} }
} }
@ -411,7 +398,7 @@ namespace Kernel
while (!m_output.flush) 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_mutex));
if (m_output.bytes == 0) if (m_output.buffer->empty())
{ {
if (master_has_closed()) if (master_has_closed())
return 0; return 0;
@ -419,19 +406,19 @@ namespace Kernel
return 0; return 0;
} }
const size_t max_to_copy = BAN::Math::min<size_t>(buffer.size(), m_output.bytes); auto data = m_output.buffer->get_data();
const size_t max_to_copy = BAN::Math::min<size_t>(buffer.size(), data.size());
size_t to_copy = max_to_copy; size_t to_copy = max_to_copy;
if (m_termios.c_lflag & ICANON) if (m_termios.c_lflag & ICANON)
for (to_copy = 1; to_copy < max_to_copy; to_copy++) for (to_copy = 1; to_copy < max_to_copy; to_copy++)
if (m_output.buffer[to_copy - 1] == NL) if (data[to_copy - 1] == NL)
break; break;
memcpy(buffer.data(), m_output.buffer.data(), to_copy); memcpy(buffer.data(), data.data(), to_copy);
m_output.buffer->pop(to_copy);
memmove(m_output.buffer.data(), m_output.buffer.data() + to_copy, m_output.bytes - to_copy); if (m_output.buffer->empty())
m_output.bytes -= to_copy;
if (m_output.bytes == 0)
m_output.flush = false; m_output.flush = false;
m_output.thread_blocker.unblock(); m_output.thread_blocker.unblock();