Kernel: Make pseudo terminals not overwrite old data

If pseudo terminal buffer was filled, old implementation would overwrite
old data. This is bad if producer is capable of producing more data than
consumer can handle.
This commit is contained in:
2025-04-23 22:02:17 +03:00
parent 73f9de6635
commit 9f4cb5c4dd
8 changed files with 36 additions and 27 deletions

View File

@@ -85,16 +85,19 @@ namespace Kernel
return BAN::Error::from_errno(ENODEV);
}
void PseudoTerminalMaster::putchar(uint8_t ch)
bool PseudoTerminalMaster::putchar(uint8_t ch)
{
SpinLockGuard _(m_buffer_lock);
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
if (m_buffer_size >= m_buffer->size())
return false;
if (m_buffer_size < m_buffer->size())
m_buffer_size++;
else
m_buffer_tail = (m_buffer_tail + 1) % m_buffer->size();
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
m_buffer_size++;
m_buffer_blocker.unblock();
return true;
}
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
@@ -166,10 +169,11 @@ namespace Kernel
(void)write_impl(0, BAN::ConstByteSpan::from(message));
}
void PseudoTerminalSlave::putchar_impl(uint8_t ch)
bool PseudoTerminalSlave::putchar_impl(uint8_t ch)
{
if (auto master = m_master.lock())
master->putchar(ch);
return master->putchar(ch);
return false;
}
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)

View File

@@ -258,9 +258,10 @@ namespace Kernel
return m_serial.height();
}
void SerialTTY::putchar_impl(uint8_t ch)
bool SerialTTY::putchar_impl(uint8_t ch)
{
m_serial.putchar(ch);
return true;
}
}

View File

@@ -327,11 +327,12 @@ namespace Kernel
}
}
void TTY::putchar(uint8_t ch)
bool TTY::putchar(uint8_t ch)
{
SpinLockGuard _(m_write_lock);
if (m_tty_ctrl.draw_graphics)
putchar_impl(ch);
return putchar_impl(ch);
return true;
}
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
@@ -365,10 +366,12 @@ namespace Kernel
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
{
SpinLockGuard _(m_write_lock);
for (size_t i = 0; i < buffer.size(); i++)
putchar(buffer[i]);
size_t written = 0;
for (; written < buffer.size(); written++)
if (!putchar(buffer[written]))
break;
update_cursor();
return buffer.size();
return written;
}
void TTY::putchar_current(uint8_t ch)

View File

@@ -501,7 +501,7 @@ namespace Kernel
scroll_if_needed();
}
void VirtualTTY::putchar_impl(uint8_t ch)
bool VirtualTTY::putchar_impl(uint8_t ch)
{
ASSERT(m_write_lock.current_processor_has_lock());
@@ -531,10 +531,10 @@ namespace Kernel
{
reset_ansi();
dprintln_if(DEBUG_VTTY, "invalid utf8");
return;
return true;
}
m_state = State::WaitingUTF8;
return;
return true;
case State::WaitingAnsiEscape:
if (ch == CSI)
m_state = State::WaitingAnsiCSI;
@@ -543,21 +543,21 @@ namespace Kernel
reset_ansi();
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
}
return;
return true;
case State::WaitingAnsiCSI:
handle_ansi_csi(ch);
return;
return true;
case State::WaitingUTF8:
if ((ch & 0xC0) != 0x80)
{
m_state = State::Normal;
dprintln_if(DEBUG_VTTY, "invalid utf8");
return;
return true;
}
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
m_utf8_state.bytes_missing--;
if (m_utf8_state.bytes_missing)
return;
return true;
m_state = State::Normal;
codepoint = m_utf8_state.codepoint;
break;
@@ -566,6 +566,7 @@ namespace Kernel
}
putcodepoint(codepoint);
return true;
}
void VirtualTTY::update_cursor()