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

View File

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