From 9f4cb5c4dd5cd80fedd4d1ae47810d8fdba3ec91 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 23 Apr 2025 22:02:17 +0300 Subject: [PATCH] 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. --- .../include/kernel/Terminal/PseudoTerminal.h | 4 ++-- kernel/include/kernel/Terminal/Serial.h | 2 +- kernel/include/kernel/Terminal/TTY.h | 4 ++-- kernel/include/kernel/Terminal/VirtualTTY.h | 2 +- kernel/kernel/Terminal/PseudoTerminal.cpp | 20 +++++++++++-------- kernel/kernel/Terminal/Serial.cpp | 3 ++- kernel/kernel/Terminal/TTY.cpp | 13 +++++++----- kernel/kernel/Terminal/VirtualTTY.cpp | 15 +++++++------- 8 files changed, 36 insertions(+), 27 deletions(-) diff --git a/kernel/include/kernel/Terminal/PseudoTerminal.h b/kernel/include/kernel/Terminal/PseudoTerminal.h index 731ecd45..29d80e82 100644 --- a/kernel/include/kernel/Terminal/PseudoTerminal.h +++ b/kernel/include/kernel/Terminal/PseudoTerminal.h @@ -20,7 +20,7 @@ namespace Kernel BAN::ErrorOr ptsname(); - void putchar(uint8_t ch); + bool putchar(uint8_t ch); protected: BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; @@ -61,7 +61,7 @@ namespace Kernel void clear() override; protected: - void putchar_impl(uint8_t ch) override; + bool putchar_impl(uint8_t ch) override; BAN::ErrorOr ioctl_impl(int, void*) override; diff --git a/kernel/include/kernel/Terminal/Serial.h b/kernel/include/kernel/Terminal/Serial.h index 14a80bca..ce1d6f8c 100644 --- a/kernel/include/kernel/Terminal/Serial.h +++ b/kernel/include/kernel/Terminal/Serial.h @@ -53,7 +53,7 @@ namespace Kernel protected: virtual BAN::StringView name() const override { return m_name; } - virtual void putchar_impl(uint8_t) override; + virtual bool putchar_impl(uint8_t) override; private: SerialTTY(Serial); diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index bf2749b8..d2be6e63 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -58,14 +58,14 @@ namespace Kernel protected: TTY(mode_t mode, uid_t uid, gid_t gid); - virtual void putchar_impl(uint8_t ch) = 0; + virtual bool putchar_impl(uint8_t ch) = 0; virtual void update_cursor() {} virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; private: - void putchar(uint8_t ch); + bool putchar(uint8_t ch); void do_backspace(); protected: diff --git a/kernel/include/kernel/Terminal/VirtualTTY.h b/kernel/include/kernel/Terminal/VirtualTTY.h index f2e40afc..d4f3cf02 100644 --- a/kernel/include/kernel/Terminal/VirtualTTY.h +++ b/kernel/include/kernel/Terminal/VirtualTTY.h @@ -26,7 +26,7 @@ namespace Kernel protected: virtual BAN::StringView name() const override { return m_name; } - virtual void putchar_impl(uint8_t ch) override; + virtual bool putchar_impl(uint8_t ch) override; void update_cursor() override; private: diff --git a/kernel/kernel/Terminal/PseudoTerminal.cpp b/kernel/kernel/Terminal/PseudoTerminal.cpp index 6f2428b4..a6b78ecb 100644 --- a/kernel/kernel/Terminal/PseudoTerminal.cpp +++ b/kernel/kernel/Terminal/PseudoTerminal.cpp @@ -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(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(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch; + m_buffer_size++; + + m_buffer_blocker.unblock(); + + return true; } BAN::ErrorOr 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 PseudoTerminalSlave::ioctl_impl(int request, void* argument) diff --git a/kernel/kernel/Terminal/Serial.cpp b/kernel/kernel/Terminal/Serial.cpp index f00bb3d3..bcc68831 100644 --- a/kernel/kernel/Terminal/Serial.cpp +++ b/kernel/kernel/Terminal/Serial.cpp @@ -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; } } diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index e99b5d78..4f3bcb1b 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -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 TTY::read_impl(off_t, BAN::ByteSpan buffer) @@ -365,10 +366,12 @@ namespace Kernel BAN::ErrorOr 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) diff --git a/kernel/kernel/Terminal/VirtualTTY.cpp b/kernel/kernel/Terminal/VirtualTTY.cpp index 4f60d534..f11a2290 100644 --- a/kernel/kernel/Terminal/VirtualTTY.cpp +++ b/kernel/kernel/Terminal/VirtualTTY.cpp @@ -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()