From d2046e79cfd915429b4755ef8e1338a1baa7815f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 16 Nov 2018 17:56:18 +0100 Subject: [PATCH] Add a DoubleBuffer thingy to allow TTY read/write to be interleaved. I feel like this concept might be useful in more places. It's very naive right now and uses dynamically growing buffers. It should really use static size buffers and never kmalloc(). --- AK/Vector.h | 8 ++++++++ Kernel/TTY.cpp | 42 +++++++++++++++++++++++++++++++----------- Kernel/TTY.h | 25 ++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/AK/Vector.h b/AK/Vector.h index 8824e10a46..d52cea64e2 100644 --- a/AK/Vector.h +++ b/AK/Vector.h @@ -188,6 +188,14 @@ public: ++m_impl->m_size; } + void append(const T* values, size_t count) + { + ensureCapacity(size() + count); + for (size_t i = 0; i < count; ++i) + new (m_impl->slot(m_impl->m_size + i)) T(values[i]); + m_impl->m_size += count; + } + void ensureCapacity(size_t neededCapacity) { if (capacity() >= neededCapacity) diff --git a/Kernel/TTY.cpp b/Kernel/TTY.cpp index 754bef3f52..fca09c7f00 100644 --- a/Kernel/TTY.cpp +++ b/Kernel/TTY.cpp @@ -4,6 +4,32 @@ #include #include +void DoubleBuffer::flip() +{ + ASSERT(m_read_buffer_index == m_read_buffer->size()); + swap(m_read_buffer, m_write_buffer); + m_write_buffer->clear(); + m_read_buffer_index = 0; +} + +Unix::ssize_t DoubleBuffer::write(const byte* data, size_t size) +{ + m_write_buffer->append(data, size); + return size; +} + +Unix::ssize_t DoubleBuffer::read(byte* data, size_t size) +{ + if (m_read_buffer_index >= m_read_buffer->size() && !m_write_buffer->isEmpty()) + flip(); + if (m_read_buffer_index >= m_read_buffer->size()) + return 0; + ssize_t nread = min(m_read_buffer->size() - m_read_buffer_index, size); + memcpy(data, m_read_buffer->data() + m_read_buffer_index, nread); + m_read_buffer_index += nread; + return nread; +} + TTY::TTY(unsigned major, unsigned minor) : CharacterDevice(major, minor) { @@ -17,15 +43,7 @@ TTY::~TTY() ssize_t TTY::read(byte* buffer, size_t size) { - ssize_t nread = min(m_buffer.size(), size); - memcpy(buffer, m_buffer.data(), nread); - if (nread == (ssize_t)m_buffer.size()) - m_buffer.clear(); - else { - kprintf("had %u, read %u\n", m_buffer.size(), nread); - ASSERT_NOT_REACHED(); - } - return nread; + return m_buffer.read(buffer, size); } ssize_t TTY::write(const byte* buffer, size_t size) @@ -36,12 +54,12 @@ ssize_t TTY::write(const byte* buffer, size_t size) bool TTY::hasDataAvailableForRead() const { - return !m_buffer.isEmpty(); + return !m_buffer.is_empty(); } void TTY::emit(byte ch) { - m_buffer.append(ch); + m_buffer.write(&ch, 1); } void TTY::interrupt() @@ -93,6 +111,8 @@ int TTY::ioctl(Process& process, unsigned request, unsigned arg) *tp = m_termios; return 0; case TCSETS: + case TCSETSF: + case TCSETSW: tp = reinterpret_cast(arg); if (!process.validate_read(tp, sizeof(Unix::termios))) return -EFAULT; diff --git a/Kernel/TTY.h b/Kernel/TTY.h index 8018012ce0..b1a45ab9a2 100644 --- a/Kernel/TTY.h +++ b/Kernel/TTY.h @@ -5,6 +5,29 @@ class Process; +class DoubleBuffer { +public: + DoubleBuffer() + : m_write_buffer(&m_buffer1) + , m_read_buffer(&m_buffer2) + { + } + + Unix::ssize_t write(const byte*, size_t); + Unix::ssize_t read(byte*, size_t); + + bool is_empty() const { return m_read_buffer_index >= m_read_buffer->size() && m_write_buffer->isEmpty(); } + +private: + void flip(); + + Vector* m_write_buffer { nullptr }; + Vector* m_read_buffer { nullptr }; + Vector m_buffer1; + Vector m_buffer2; + size_t m_read_buffer_index { 0 }; +}; + class TTY : public CharacterDevice { public: virtual ~TTY() override; @@ -35,7 +58,7 @@ protected: void interrupt(); private: - Vector m_buffer; + DoubleBuffer m_buffer; pid_t m_pgid { 0 }; Unix::termios m_termios; };