Add a new observable, gdb::observers::terminal_owner_changed.
Its observers are notified when gdb_tty_state changes.
On each change, they are notified twice:
- once with the old gdb_tty_state, and active == false, and
- once with the new gdb_tty_state, and active == true.
No functional changes.
Tested on x86_64-linux.
---
gdb/inflow.c | 176 ++++++++++++++++++++++++++---------------------
gdb/observable.c | 1 +
gdb/observable.h | 5 ++
3 files changed, 103 insertions(+), 79 deletions(-)
@@ -311,67 +311,76 @@ child_terminal_inferior (struct target_ops *self)
inferior *inf = current_inferior ();
terminal_info *tinfo = get_inflow_inferior_data (inf);
- if (gdb_has_a_terminal ()
- && tinfo->ttystate != NULL
- && sharing_input_terminal (inf))
- {
- int result;
+ if (!(gdb_has_a_terminal ()
+ && tinfo->ttystate != NULL
+ && sharing_input_terminal (inf)))
+ return;
- /* Ignore SIGTTOU since it will happen when we try to set the
- terminal's state (if gdb_tty_state is currently
- ours_for_output). */
- scoped_ignore_sigttou ignore_sigttou;
+ /* Note that the old state will no longer be active. */
+ gdb::observers::terminal_owner_changed.notify (gdb_tty_state, false);
+
+ /* Scope containing scoped_ignore_sigtto. */
+ {
+ int result;
+
+ /* Ignore SIGTTOU since it will happen when we try to set the
+ terminal's state (if gdb_tty_state is currently
+ ours_for_output). */
+ scoped_ignore_sigttou ignore_sigttou;
#ifdef F_GETFL
- result = fcntl (0, F_SETFL, tinfo->tflags);
- OOPSY ("fcntl F_SETFL");
+ result = fcntl (0, F_SETFL, tinfo->tflags);
+ OOPSY ("fcntl F_SETFL");
#endif
- result = serial_set_tty_state (stdin_serial, tinfo->ttystate);
- OOPSY ("setting tty state");
+ result = serial_set_tty_state (stdin_serial, tinfo->ttystate);
+ OOPSY ("setting tty state");
- if (!job_control)
- {
- sigint_ours = install_sigint_handler (SIG_IGN);
+ if (!job_control)
+ {
+ sigint_ours = install_sigint_handler (SIG_IGN);
#ifdef SIGQUIT
- sigquit_ours = signal (SIGQUIT, SIG_IGN);
+ sigquit_ours = signal (SIGQUIT, SIG_IGN);
#endif
- }
+ }
- if (job_control)
- {
+ if (job_control)
+ {
#ifdef HAVE_TERMIOS_H
- /* If we can't tell the inferior's actual process group,
- then restore whatever was the foreground pgrp the last
- time the inferior was running. See also comments
- describing terminal_state::process_group. */
+ /* If we can't tell the inferior's actual process group,
+ then restore whatever was the foreground pgrp the last
+ time the inferior was running. See also comments
+ describing terminal_state::process_group. */
#ifdef HAVE_GETPGID
- result = tcsetpgrp (0, getpgid (inf->pid));
+ result = tcsetpgrp (0, getpgid (inf->pid));
#else
- result = tcsetpgrp (0, tinfo->process_group);
+ result = tcsetpgrp (0, tinfo->process_group);
#endif
- if (result == -1)
- {
+ if (result == -1)
+ {
#if 0
- /* This fails if either GDB has no controlling terminal,
- e.g., running under 'setsid(1)', or if the inferior
- is not attached to GDB's controlling terminal. E.g.,
- if it called setsid to create a new session or used
- the TIOCNOTTY ioctl, or simply if we've attached to a
- process running on another terminal and we couldn't
- tell whether it was sharing GDB's terminal (and so
- assumed yes). */
- gdb_printf
- (gdb_stderr,
- "[tcsetpgrp failed in child_terminal_inferior: %s]\n",
- safe_strerror (errno));
+ /* This fails if either GDB has no controlling terminal,
+ e.g., running under 'setsid(1)', or if the inferior
+ is not attached to GDB's controlling terminal. E.g.,
+ if it called setsid to create a new session or used
+ the TIOCNOTTY ioctl, or simply if we've attached to a
+ process running on another terminal and we couldn't
+ tell whether it was sharing GDB's terminal (and so
+ assumed yes). */
+ gdb_printf
+ (gdb_stderr,
+ "[tcsetpgrp failed in child_terminal_inferior: %s]\n",
+ safe_strerror (errno));
#endif
- }
+ }
#endif
- }
+ }
- gdb_tty_state = target_terminal_state::is_inferior;
- }
+ gdb_tty_state = target_terminal_state::is_inferior;
+ }
+
+ /* Note that the new state is active. */
+ gdb::observers::terminal_owner_changed.notify (gdb_tty_state, true);
}
/* Put some of our terminal settings into effect,
@@ -447,55 +456,64 @@ child_terminal_ours_1 (target_terminal_state desired_state)
if (!gdb_has_a_terminal ())
return;
- if (gdb_tty_state != desired_state)
- {
- int result ATTRIBUTE_UNUSED;
+ if (gdb_tty_state == desired_state)
+ return;
- /* Ignore SIGTTOU since it will happen when we try to set the
- terminal's pgrp. */
- scoped_ignore_sigttou ignore_sigttou;
+ /* Note that the old state will no longer be active. */
+ gdb::observers::terminal_owner_changed.notify (gdb_tty_state, false);
- /* Set tty state to our_ttystate. */
- serial_set_tty_state (stdin_serial, our_terminal_info.ttystate);
+ /* Scope containing scoped_ignore_sigtto. */
+ {
+ int result ATTRIBUTE_UNUSED;
- /* If we only want output, then leave the inferior's pgrp in the
- foreground, so that Ctrl-C/Ctrl-Z reach the inferior
- directly. */
- if (job_control && desired_state == target_terminal_state::is_ours)
- {
+ /* Ignore SIGTTOU since it will happen when we try to set the
+ terminal's pgrp. */
+ scoped_ignore_sigttou ignore_sigttou;
+
+ /* Set tty state to our_ttystate. */
+ serial_set_tty_state (stdin_serial, our_terminal_info.ttystate);
+
+ /* If we only want output, then leave the inferior's pgrp in the
+ foreground, so that Ctrl-C/Ctrl-Z reach the inferior
+ directly. */
+ if (job_control && desired_state == target_terminal_state::is_ours)
+ {
#ifdef HAVE_TERMIOS_H
- result = tcsetpgrp (0, our_terminal_info.process_group);
+ result = tcsetpgrp (0, our_terminal_info.process_group);
#if 0
- /* This fails on Ultrix with EINVAL if you run the testsuite
- in the background with nohup, and then log out. GDB never
- used to check for an error here, so perhaps there are other
- such situations as well. */
- if (result == -1)
- gdb_printf (gdb_stderr,
- "[tcsetpgrp failed in child_terminal_ours: %s]\n",
- safe_strerror (errno));
+ /* This fails on Ultrix with EINVAL if you run the testsuite
+ in the background with nohup, and then log out. GDB never
+ used to check for an error here, so perhaps there are other
+ such situations as well. */
+ if (result == -1)
+ gdb_printf (gdb_stderr,
+ "[tcsetpgrp failed in child_terminal_ours: %s]\n",
+ safe_strerror (errno));
#endif
#endif /* termios */
- }
+ }
- if (!job_control && desired_state == target_terminal_state::is_ours)
- {
- if (sigint_ours.has_value ())
- install_sigint_handler (*sigint_ours);
- sigint_ours.reset ();
+ if (!job_control && desired_state == target_terminal_state::is_ours)
+ {
+ if (sigint_ours.has_value ())
+ install_sigint_handler (*sigint_ours);
+ sigint_ours.reset ();
#ifdef SIGQUIT
- if (sigquit_ours.has_value ())
- signal (SIGQUIT, *sigquit_ours);
- sigquit_ours.reset ();
+ if (sigquit_ours.has_value ())
+ signal (SIGQUIT, *sigquit_ours);
+ sigquit_ours.reset ();
#endif
- }
+ }
#ifdef F_GETFL
- result = fcntl (0, F_SETFL, our_terminal_info.tflags);
+ result = fcntl (0, F_SETFL, our_terminal_info.tflags);
#endif
- gdb_tty_state = desired_state;
- }
+ gdb_tty_state = desired_state;
+ }
+
+ /* Note that the new state is active. */
+ gdb::observers::terminal_owner_changed.notify (gdb_tty_state, true);
}
/* Interrupt the inferior. Implementation of target_interrupt for
@@ -82,6 +82,7 @@ DEFINE_OBSERVABLE (gdb_exiting);
DEFINE_OBSERVABLE (connection_removed);
DEFINE_OBSERVABLE (target_pre_wait);
DEFINE_OBSERVABLE (target_post_wait);
+DEFINE_OBSERVABLE (terminal_owner_changed);
} /* namespace observers */
} /* namespace gdb */
@@ -22,6 +22,7 @@
#include "gdbsupport/observable.h"
#include "target/waitstatus.h"
+#include "target/target.h"
struct bpstat;
struct so_list;
@@ -276,6 +277,10 @@ extern observable <ptid_t /* ptid */> target_pre_wait;
/* About to leave target_wait (). */
extern observable <ptid_t /* event_ptid */> target_post_wait;
+/* When the terminal owner changes. */
+extern observable <target_terminal_state /* gdb_tty_state */, bool /* active */>
+ terminal_owner_changed;
+
} /* namespace observers */
} /* namespace gdb */