Index: lldb/include/lldb/Host/Terminal.h =================================================================== --- lldb/include/lldb/Host/Terminal.h +++ lldb/include/lldb/Host/Terminal.h @@ -13,8 +13,6 @@ #include "lldb/Host/Config.h" #include "lldb/lldb-private.h" -struct termios; - namespace lldb_private { class Terminal { @@ -41,17 +39,29 @@ int m_fd; // This may or may not be a terminal file descriptor }; -/// \class State Terminal.h "lldb/Host/Terminal.h" -/// A terminal state saving/restoring class. +/// \class TerminalState Terminal.h "lldb/Host/Terminal.h" +/// A RAII-friendly terminal state saving/restoring class. /// /// This class can be used to remember the terminal state for a file /// descriptor and later restore that state as it originally was. class TerminalState { + class Impl; + public: - /// Default constructor - TerminalState(); + /// Construct a new instance and optionally save terminal state. + /// + /// \param[in] term + /// The Terminal instance holding the file descriptor to save the state + /// of. If the instance is not associated with a fd, no state will + /// be saved. + /// + /// \param[in] save_process_group + /// If \b true, save the process group settings, else do not + /// save the process group settings for a TTY. + TerminalState(Terminal term = -1, bool save_process_group = false); - /// Destructor + /// Destroy the instance, restoring terminal state if saved. If restoring + /// state is undesirable, the instance needs to be reset before destruction. ~TerminalState(); /// Save the TTY state for \a fd. @@ -60,8 +70,8 @@ /// "save_process_group" is true, attempt to save the process group info for /// the TTY. /// - /// \param[in] fd - /// The file descriptor to save the state of. + /// \param[in] term + /// The Terminal instance holding fd to save. /// /// \param[in] save_process_group /// If \b true, save the process group settings, else do not @@ -70,7 +80,7 @@ /// \return /// Returns \b true if \a fd describes a TTY and if the state /// was able to be saved, \b false otherwise. - bool Save(int fd, bool save_process_group); + bool Save(Terminal term, bool save_process_group); /// Restore the TTY state to the cached state. /// @@ -115,12 +125,9 @@ bool ProcessGroupIsValid() const; // Member variables - Terminal m_tty; ///< A terminal - int m_tflags = -1; ///< Cached tflags information. -#if LLDB_ENABLE_TERMIOS - std::unique_ptr - m_termios_up; ///< Cached terminal state information. -#endif + Terminal m_tty; ///< A terminal + int m_tflags = -1; ///< Cached tflags information. + std::unique_ptr m_data; ///< Platform-specific implementation. lldb::pid_t m_process_group = -1; ///< Cached process group information. }; Index: lldb/source/Host/common/Terminal.cpp =================================================================== --- lldb/source/Host/common/Terminal.cpp +++ lldb/source/Host/common/Terminal.cpp @@ -81,63 +81,59 @@ return false; } -// Default constructor -TerminalState::TerminalState() - : m_tty() +class TerminalState::Impl { #if LLDB_ENABLE_TERMIOS - , - m_termios_up() + struct termios m_termios; ///< Cached terminal state information. #endif -{ + +public: + static llvm::Optional Save(Terminal term) { +#if LLDB_ENABLE_TERMIOS + Impl ret; + if (::tcgetattr(term.GetFileDescriptor(), &ret.m_termios) != 0) + return ret; +#endif // LLDB_ENABLE_TERMIOS + return llvm::None; + } + + void Restore(Terminal term) { +#if LLDB_ENABLE_TERMIOS + tcsetattr(term.GetFileDescriptor(), TCSANOW, &m_termios); +#endif // LLDB_ENABLE_TERMIOS + } +}; + +TerminalState::TerminalState(Terminal term, bool save_process_group) + : m_tty(term) { + Save(term, save_process_group); } -// Destructor -TerminalState::~TerminalState() = default; +TerminalState::~TerminalState() { Restore(); } void TerminalState::Clear() { m_tty.Clear(); m_tflags = -1; -#if LLDB_ENABLE_TERMIOS - m_termios_up.reset(); -#endif + m_data.reset(); m_process_group = -1; } -// Save the current state of the TTY for the file descriptor "fd" and if -// "save_process_group" is true, attempt to save the process group info for the -// TTY. -bool TerminalState::Save(int fd, bool save_process_group) { - m_tty.SetFileDescriptor(fd); +bool TerminalState::Save(Terminal term, bool save_process_group) { + Clear(); + m_tty = term; if (m_tty.IsATerminal()) { + int fd = m_tty.GetFileDescriptor(); #if LLDB_ENABLE_POSIX m_tflags = ::fcntl(fd, F_GETFL, 0); -#endif -#if LLDB_ENABLE_TERMIOS - if (m_termios_up == nullptr) - m_termios_up.reset(new struct termios); - int err = ::tcgetattr(fd, m_termios_up.get()); - if (err != 0) - m_termios_up.reset(); -#endif // #if LLDB_ENABLE_TERMIOS -#if LLDB_ENABLE_POSIX + llvm::Optional impl_state = Impl::Save(m_tty); + if (impl_state) + m_data.reset(new Impl(impl_state.getValue())); if (save_process_group) - m_process_group = ::tcgetpgrp(0); - else - m_process_group = -1; -#endif - } else { - m_tty.Clear(); - m_tflags = -1; -#if LLDB_ENABLE_TERMIOS - m_termios_up.reset(); -#endif - m_process_group = -1; + m_process_group = ::tcgetpgrp(fd); +#endif // LLDB_ENABLE_POSIX } return IsValid(); } -// Restore the state of the TTY using the cached values from a previous call to -// Save(). bool TerminalState::Restore() const { #if LLDB_ENABLE_POSIX if (IsValid()) { @@ -145,10 +141,8 @@ if (TFlagsIsValid()) fcntl(fd, F_SETFL, m_tflags); -#if LLDB_ENABLE_TERMIOS if (TTYStateIsValid()) - tcsetattr(fd, TCSANOW, m_termios_up.get()); -#endif // #if LLDB_ENABLE_TERMIOS + m_data->Restore(m_tty); if (ProcessGroupIsValid()) { // Save the original signal handler. @@ -161,30 +155,19 @@ } return true; } -#endif +#endif // LLDB_ENABLE_POSIX return false; } -// Returns true if this object has valid saved TTY state settings that can be -// used to restore a previous state. bool TerminalState::IsValid() const { return m_tty.FileDescriptorIsValid() && - (TFlagsIsValid() || TTYStateIsValid()); + (TFlagsIsValid() || TTYStateIsValid() || ProcessGroupIsValid()); } -// Returns true if m_tflags is valid bool TerminalState::TFlagsIsValid() const { return m_tflags != -1; } -// Returns true if m_ttystate is valid -bool TerminalState::TTYStateIsValid() const { -#if LLDB_ENABLE_TERMIOS - return m_termios_up != nullptr; -#else - return false; -#endif -} +bool TerminalState::TTYStateIsValid() const { return bool(m_data); } -// Returns true if m_process_group is valid bool TerminalState::ProcessGroupIsValid() const { return static_cast(m_process_group) != -1; } Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -355,7 +355,6 @@ PyEval_InitThreads(); } - TerminalState m_stdin_tty_state; PyGILState_STATE m_gil_state = PyGILState_UNLOCKED; bool m_was_already_initialized = false; }; Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -430,11 +430,9 @@ int stdin_fd = GetInputFD(); if (stdin_fd >= 0) { Terminal terminal(stdin_fd); - TerminalState terminal_state; - const bool is_a_tty = terminal.IsATerminal(); + TerminalState terminal_state(terminal); - if (is_a_tty) { - terminal_state.Save(stdin_fd, false); + if (terminal.IsATerminal()) { terminal.SetCanonical(false); terminal.SetEcho(true); } @@ -464,9 +462,6 @@ run_string.Printf("run_python_interpreter (%s)", m_python->GetDictionaryName()); PyRun_SimpleString(run_string.GetData()); - - if (is_a_tty) - terminal_state.Restore(); } } SetIsDone(true); Index: lldb/source/Target/Process.cpp =================================================================== --- lldb/source/Target/Process.cpp +++ lldb/source/Target/Process.cpp @@ -4351,9 +4351,8 @@ SetIsDone(false); const int read_fd = m_read_file.GetDescriptor(); - TerminalState terminal_state; - terminal_state.Save(read_fd, false); Terminal terminal(read_fd); + TerminalState terminal_state(terminal, false); terminal.SetCanonical(false); terminal.SetEcho(false); // FD_ZERO, FD_SET are not supported on windows @@ -4399,7 +4398,6 @@ } m_is_running = false; #endif - terminal_state.Restore(); } void Cancel() override {