[PATCH] Save and restore tty attributes



Hello,

Tom Hughes attached a patch to bugzilla[1] to save and restore the
attributes of the tty shared by Nemiver and the inferior program being
debugged.

[1]: https://bugzilla.gnome.org/show_bug.cgi?id=663862

After discussing with Tom, I have updated, tested and applied the
patch to the master branch.  Below is his cover letter as well as the
amended patch as applied.

Many thanks to Tom.

    Before starting the debugger for the first time, save the terminal
    settings and then restore them whenever we start the target and when
    we are exiting so that any changes made to the terminal setting by
    the target are discarded.

	* src/dbgengine/nmv-i-debugger.h (IDebugger::load_program): Take
	additional slave_tty_fd and uses_launch_tty parameters.
	* src/dbgengine/nmv-gdb-engine.h (GDBEngine::load_program):
	Likewise.
	* src/dbgengine/nmv-gdb-engine.cc
	(GDBengine::Priv::{uses_launch_tty, tt_attributes, tty_path,
	tty_fd): New members.
	(GDBEngine::Priv::Priv): Initialize the new members above.
	(GDBEngine::Priv::{get_tty_attributes,set_tty_attributes}): New
	functions.
	(GDBEngine::Priv::issue_command): When issuing a "re-run" command
	make sure to re-set the tty attribute to their initial state.
	(GDBEngine::load_program): In compliance with the above change on
	the interface of this function, Take additional slave_tty_fd and
	uses_launch_tty parameters.  Call new m_priv->get_tty_attributes before
	really launching GDB.  Adjust call from load_program overload.
	Update comment.
	(GDBEngine::exit_engine): Call new m_priv->set_tty_attributes
	after debugger exited.  Add comment.
	* src/uicommon/nmv-terminal.h (Terminal::slave_ptr): Declare ...
	* src/uicommon/nmv-terminal.cc (Terminal::slave_pty): ... new
	function.
	* src/persp/dbgperspective/nmv-dbg-perspective.cc
	(DBGPerspective::execute_program): Adjust call to the
	IDebugger::load_program.
	(DBGPerspective::on_shutdown_signal): Re-indent comment.
	(DBGPerspective::get_terminal_name): Add comment.

Signed-off-by: Dodji Seketeli <dodji seketeli org>
---
 src/dbgengine/nmv-gdb-engine.cc                 |   77 +++++++++++++++++++++--
 src/dbgengine/nmv-gdb-engine.h                  |    4 +-
 src/dbgengine/nmv-i-debugger.h                  |    4 +-
 src/persp/dbgperspective/nmv-dbg-perspective.cc |   16 ++++-
 src/uicommon/nmv-terminal.cc                    |   10 +++
 src/uicommon/nmv-terminal.h                     |    1 +
 6 files changed, 103 insertions(+), 9 deletions(-)

diff --git a/src/dbgengine/nmv-gdb-engine.cc b/src/dbgengine/nmv-gdb-engine.cc
index 8140bf5..2bb076f 100644
--- a/src/dbgengine/nmv-gdb-engine.cc
+++ b/src/dbgengine/nmv-gdb-engine.cc
@@ -222,6 +222,10 @@ public:
     OutputHandlerList output_handler_list;
     IDebugger::State state;
     bool is_running;
+    bool uses_launch_tty;
+    struct termios tty_attributes;
+    string tty_path;
+    int tty_fd;
     int cur_frame_level;
     int cur_thread_num;
     Address cur_frame_address;
@@ -565,6 +569,8 @@ public:
         error_buffer_status (DEFAULT),
         state (IDebugger::NOT_STARTED),
         is_running (false),
+        uses_launch_tty (false),
+        tty_fd (-1),
         cur_frame_level (0),
         cur_thread_num (1),
         follow_fork_mode ("parent"),
@@ -573,6 +579,7 @@ public:
         enable_pretty_printing (true),
         pretty_printing_enabled_once (false)
     {
+        memset (&tty_attributes, 0, sizeof (tty_attributes));
 
         enable_pretty_printing =
             g_getenv ("NMV_DISABLE_PRETTY_PRINTING") == 0;
@@ -688,6 +695,37 @@ public:
         }
     }
 
+    /// Read the attributes of the low level tty used by Nemiver's
+    /// terminal and the inferior to communicate.  The attributes are
+    /// then stored memory.
+    void get_tty_attributes ()
+    {
+        LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+        if (uses_launch_tty && isatty (0)) {
+            tcgetattr (0, &tty_attributes);
+        } else if (tty_fd >= 0) {
+            tcgetattr (tty_fd,
+                       &tty_attributes);
+        }
+    }
+
+    /// Set the attributes (previously saved by get_tty_attributes)
+    /// from memory to the low level tty used by Nemiver's terminal
+    /// and the inferior to communicate.
+    void set_tty_attributes ()
+    {
+        LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+        if (uses_launch_tty && isatty (0)) {
+            tcsetattr (0, TCSANOW, &tty_attributes);
+        } else if (tty_fd >= 0){
+            tcsetattr (tty_fd,
+                       TCSANOW,
+                       &tty_attributes);
+        }
+    }
+
     bool launch_gdb_real (const vector<UString> a_argv)
     {
         RETURN_VAL_IF_FAIL (launch_program (a_argv,
@@ -872,6 +910,14 @@ public:
         LOG_DD ("issuing command: '" << a_command.value () << "': name: '"
                 << a_command.name () << "'");
 
+        if (a_command.name () == "re-run") {
+            // Before restarting the target, re-set the tty attributes
+            // so that the tty has a chance to comes back into cook
+            // mode.  Some targets might expect this behaviour.
+            LOG_DD ("Restoring tty attributes");
+            set_tty_attributes ();
+        }
+
         if (master_pty_channel->write
                 (a_command.value () + "\n") == Glib::IO_STATUS_NORMAL) {
             master_pty_channel->flush ();
@@ -3100,7 +3146,10 @@ GDBEngine::load_program (const UString &a_prog,
     vector<UString> search_paths;
     UString tty_path;
     return load_program (a_prog, a_args, a_working_dir,
-                         search_paths, tty_path, a_force);
+                         search_paths, tty_path, 
+                         /*slave_tty_fd*/-1,
+                         /*uses_launch_tty=*/false,
+                         a_force);
 }
 
 /// Load an inferior program to debug.
@@ -3117,7 +3166,11 @@ GDBEngine::load_program (const UString &a_prog,
 /// look for the source files of the objects that make up the inferior
 /// program.
 ///
-/// \param a_tty_path the tty path the inferior should use.
+/// \param a_slave_tty_path the tty path the inferior should use.
+///
+/// \param a_slave_tty_fd the file descriptor of the slave tty that is
+/// to be used by the inferior to communicate with the program using
+/// the current instance of GDBEngine.
 ///
 /// \param a_force if this is true and the command queue is stuck,
 /// clear it to force the loading of the inferior.
@@ -3126,7 +3179,9 @@ GDBEngine::load_program (const UString &a_prog,
                          const vector<UString> &a_argv,
                          const UString &a_working_dir,
                          const vector<UString> &a_source_search_dirs,
-                         const UString &a_tty_path,
+                         const UString &a_slave_tty_path,
+                         int a_slave_tty_fd,
+                         bool a_uses_launch_tty,
                          bool a_force)
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
@@ -3136,13 +3191,20 @@ GDBEngine::load_program (const UString &a_prog,
 
     if (!m_priv->is_gdb_running ()) {
         vector<UString> gdb_opts;
+
+        // Read the tty attributes before we launch the target so that
+        // we can restore them later at exit time, to discard the tty
+        // changes that might be done by the target.
+        m_priv->tty_fd = a_slave_tty_fd;
+        m_priv->get_tty_attributes ();
+
         if (m_priv->launch_gdb_and_set_args (a_working_dir,
                                              a_source_search_dirs, 
                                              a_prog, a_argv,
                                              gdb_opts) == false)
             return false;
 
-        Command command;
+        m_priv->uses_launch_tty = a_uses_launch_tty;
 
         // In case we are restarting GDB after a crash, the command
         // queue might be stuck.  Let's restart it.
@@ -3194,7 +3256,7 @@ GDBEngine::load_program (const UString &a_prog,
             queue_command (command);
         }
     }
-    m_priv->set_tty_path (a_tty_path, "load-program");
+    m_priv->set_tty_path (a_slave_tty_path, "load-program");
     return true;
 }
 
@@ -4360,6 +4422,7 @@ GDBEngine::stop_target ()
     return  (kill (m_priv->gdb_pid, SIGINT) == 0);
 }
 
+/// Stop the inferior and exit GDB.  Do the necessary book keeping.
 void
 GDBEngine::exit_engine ()
 {
@@ -4379,6 +4442,10 @@ GDBEngine::exit_engine ()
     //send the lethal command and run the event loop to flush everything.
     m_priv->issue_command (Command ("quit"), false);
     set_state (IDebugger::NOT_STARTED);
+
+    // Set the tty attribute back into the state it was before we
+    // connected to the target.
+    m_priv->set_tty_attributes ();
 }
 
 void
diff --git a/src/dbgengine/nmv-gdb-engine.h b/src/dbgengine/nmv-gdb-engine.h
index c027968..135992f 100644
--- a/src/dbgengine/nmv-gdb-engine.h
+++ b/src/dbgengine/nmv-gdb-engine.h
@@ -292,7 +292,9 @@ public:
                        const vector<UString> &a_argv,
                        const UString &working_dir,
                        const vector<UString> &a_source_search_dirs,
-                       const UString &a_tty_path,
+                       const UString &a_slave_tty_path,
+		       int a_slave_tty_fd,
+		       bool a_uses_launch_tty,
 		       bool a_force);
 
     void load_core_file (const UString &a_prog_file,
diff --git a/src/dbgengine/nmv-i-debugger.h b/src/dbgengine/nmv-i-debugger.h
index f9fa525..5356745 100644
--- a/src/dbgengine/nmv-i-debugger.h
+++ b/src/dbgengine/nmv-i-debugger.h
@@ -1273,7 +1273,9 @@ public:
                  const vector<UString> &a_argv,
                  const UString &working_dir,
                  const vector<UString> &a_source_search_dirs,
-                 const UString &a_tty_path,
+                 const UString &a_slave_tty_path,
+                 int a_slave_tty_fd,
+                 bool a_uses_launch_tty = false,
                  bool a_force = false) = 0;
 
     virtual void load_core_file (const UString &a_prog_file,
diff --git a/src/persp/dbgperspective/nmv-dbg-perspective.cc b/src/persp/dbgperspective/nmv-dbg-perspective.cc
index b2cc7c6..b7ad484 100644
--- a/src/persp/dbgperspective/nmv-dbg-perspective.cc
+++ b/src/persp/dbgperspective/nmv-dbg-perspective.cc
@@ -2105,8 +2105,8 @@ DBGPerspective::on_shutdown_signal ()
         return;
     }
 
-    // stop the debugger so that the target executable doesn't go on running
-    // after we shut down
+    // stop the debugger so that the target executable doesn't go on
+    // running after we shut down
     debugger ()->exit_engine ();
 
     if (m_priv->reused_session) {
@@ -6075,6 +6075,8 @@ DBGPerspective::execute_program
     if (dbg_engine->load_program (prog, a_args, a_cwd,
                                   source_search_dirs,
                                   get_terminal_name (),
+                                  uses_launch_terminal (),
+                                  get_terminal ().slave_pty (),
                                   a_restarting
                                   ? true
                                   : false) == false) {
@@ -8159,6 +8161,16 @@ DBGPerspective::get_terminal_box ()
     return *m_priv->terminal_box;
 }
 
+/// Return the path name for the tty device that the debugging
+/// perspective uses to communicate with the standard tty of the and
+/// the inferior program.
+///
+/// If Nemiver is using the terminal from which it was launch (rather
+/// than its own terminal widget), the name returned is the path name
+/// for the tty device of that "launch terminal".
+///
+/// Note that this really is the path of the device created for the
+/// slave side of the relevant pseudo terminal.
 UString
 DBGPerspective::get_terminal_name ()
 {
diff --git a/src/uicommon/nmv-terminal.cc b/src/uicommon/nmv-terminal.cc
index e925f67..81cc859 100644
--- a/src/uicommon/nmv-terminal.cc
+++ b/src/uicommon/nmv-terminal.cc
@@ -295,6 +295,16 @@ Terminal::adjustment () const
     return m_priv->adjustment;
 }
 
+/// Return the file descriptor of the slave pseudo tty used by the the
+/// proces that would want to communicate with this terminal.
+int
+Terminal::slave_pty () const
+{
+    THROW_IF_FAIL (m_priv);
+    THROW_IF_FAIL (m_priv->slave_pty);
+    return m_priv->slave_pty;
+}
+
 UString
 Terminal::slave_pts_name () const
 {
diff --git a/src/uicommon/nmv-terminal.h b/src/uicommon/nmv-terminal.h
index 6f5b9ed..d8c075d 100644
--- a/src/uicommon/nmv-terminal.h
+++ b/src/uicommon/nmv-terminal.h
@@ -66,6 +66,7 @@ public:
     ~Terminal ();
     Gtk::Widget& widget () const;
     Glib::RefPtr<Gtk::Adjustment> adjustment () const;
+    int slave_pty () const;
     UString slave_pts_name () const;
     void modify_font (const Pango::FontDescription &font_desc);
     void feed (const UString &a_text);
-- 
		Dodji


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]