diff --git a/Kernel/TTY/TTY.cpp b/Kernel/TTY/TTY.cpp index ce7c21a6780..f32e50b5edd 100644 --- a/Kernel/TTY/TTY.cpp +++ b/Kernel/TTY/TTY.cpp @@ -53,23 +53,27 @@ KResultOr TTY::read(FileDescription&, u64, UserOrKernelBuffer& buffer, s bool need_evaluate_block_conditions = false; auto result = buffer.write_buffered<512>(size, [&](u8* data, size_t data_size) { - for (size_t i = 0; i < data_size; ++i) { - u8 ch = m_input_buffer.dequeue(); - if (in_canonical_mode()) { + size_t bytes_written = 0; + for (; bytes_written < data_size; ++bytes_written) { + auto bit_index = m_input_buffer.head_index(); + bool is_special_character = m_special_character_bitmask[bit_index / 8] & (1 << (bit_index % 8)); + if (in_canonical_mode() && is_special_character) { + u8 ch = m_input_buffer.dequeue(); if (ch == '\0') { + // EOF m_available_lines--; need_evaluate_block_conditions = true; break; - } else if (ch == '\n' || is_eol(ch)) { - data[i] = ch; - i++; + } else { + // '\n' or EOL + data[bytes_written++] = ch; m_available_lines--; break; } } - data[i] = ch; + data[bytes_written] = m_input_buffer.dequeue(); } - return data_size; + return bytes_written; }); if ((!result.is_error() && result.value() > 0) || need_evaluate_block_conditions) evaluate_block_conditions(); @@ -203,11 +207,20 @@ void TTY::emit(u8 ch, bool do_evaluate_block_conditions) else if (ch == '\n' && (m_termios.c_iflag & INLCR)) ch = '\r'; + auto current_char_head_index = (m_input_buffer.head_index() + m_input_buffer.size()) % TTY_BUFFER_SIZE; + m_special_character_bitmask[current_char_head_index / 8] &= ~(1u << (current_char_head_index % 8)); + + auto set_special_bit = [&] { + m_special_character_bitmask[current_char_head_index / 8] |= (1u << (current_char_head_index % 8)); + }; + if (in_canonical_mode()) { if (is_eof(ch)) { + // Since EOF might change between when the data came in and when it is read, + // we use '\0' along with the bitmask to signal EOF. Any non-zero byte with + // the special bit set signals an end-of-line. + set_special_bit(); m_available_lines++; - //We use '\0' to delimit the end - //of a line. m_input_buffer.enqueue('\0'); return; } @@ -224,17 +237,19 @@ void TTY::emit(u8 ch, bool do_evaluate_block_conditions) return; } - if (is_eol(ch)) { - m_available_lines++; - } - if (ch == '\n') { if (m_termios.c_lflag & ECHO || m_termios.c_lflag & ECHONL) echo('\n'); + set_special_bit(); m_input_buffer.enqueue('\n'); m_available_lines++; return; } + + if (is_eol(ch)) { + set_special_bit(); + m_available_lines++; + } } m_input_buffer.enqueue(ch); diff --git a/Kernel/TTY/TTY.h b/Kernel/TTY/TTY.h index 3f5bd0efd28..a34961bad38 100644 --- a/Kernel/TTY/TTY.h +++ b/Kernel/TTY/TTY.h @@ -13,6 +13,8 @@ #include #include +#define TTY_BUFFER_SIZE 1024 + namespace Kernel { class TTY : public CharacterDevice { @@ -79,7 +81,10 @@ private: // ^CharacterDevice virtual bool is_tty() const final override { return true; } - CircularDeque m_input_buffer; + CircularDeque m_input_buffer; + // FIXME: use something like AK::Bitmap but which takes a size template parameter + u8 m_special_character_bitmask[TTY_BUFFER_SIZE / 8]; + WeakPtr m_original_process_parent; WeakPtr m_pg; termios m_termios;