[PATCH] [RFC] Discard local stdin events while an attached inferior is running

Patrick Palka
2015-06-02T13:39:31Z

This patch attempts to work around an annoying typo that I (and others,
I assume) commonly make while debugging an attached (not forked)
process. That is, I sometimes type "continue\n\n" instead of
"continue\n" when I want to resume the inferior. By doing so, the
inferior gets resumed and the extraneous "\n" gets buffered. But once
GDB regains control, the extraneous "\n" gets read and so an empty
command line is submitted to readline. This is shorthand for running
the previous command again. So effectively typing "continue\n\n" will
run "continue" twice. Running "continue" twice instead of once can have
irreversible consequences to the debugging session and thus is pretty
annoying to deal with.

To work around this kind of typo, this patch installs a dummy event
handler that discards all local stdin events that occur when the
attached inferior is (synchronously) running.

The obvious side-effect of this patch is that dexterous users can no
longer "queue" commands while an attached inferior is running, e.g.
type "continue\nprint foo" with the intention of "print foo" being run
as soon as GDB regains control. I personally don't make use of this
ability very much.

Is this typo a common occurrence for anyone else? Should this kind of
typo be worked around? Any thoughts on the this particular workaround,
or on other potential workarounds?

gdb/ChangeLog:

* event-top.h (stdin_discard_event_handler): Declare.
* event-top.c (stdin_discard_event_handler): Define.
* linux-nat.c: Include "top.h".
(linux_nat_terminal_inferior): Use stdin_discard_event_handler.
---
gdb/event-top.c | 8 ++++++++
gdb/event-top.h | 6 ++++++
gdb/linux-nat.c | 20 ++++++++++++++++++++
3 files changed, 34 insertions(+)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index e9cc2d7..5fa7ab3 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -434,6 +434,14 @@ stdin_event_handler (int error, gdb_client_data client_data)
}
}

+/* See event-top.h. */
+
+void
+stdin_discard_event_handler (int error, gdb_client_data client_data)
+{
+ (void) fgetc (instream);
+}
+
/* Re-enable stdin after the end of an execution command in
synchronous mode, or after an error from the target, and we aborted
the exec operation. */
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 8dc8c6b..bc3f331 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -47,6 +47,12 @@ extern void handle_sigterm (int sig);
extern void gdb_readline2 (void *client_data);
extern void async_request_quit (void *arg);
extern void stdin_event_handler (int error, void *client_data);
+
+/* An event handler that reads and discards one byte of data
+ from INSTREAM (usually stdin). */
+
+extern void stdin_discard_event_handler (int error, void *client_data);
+
extern void async_disable_stdin (void);
extern void async_enable_stdin (void);

diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index febee84..6384be5 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -66,6 +66,7 @@
#include "target-descriptions.h"
#include "filestuff.h"
#include "objfiles.h"
+#include "top.h"

#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@@ -4635,6 +4636,25 @@ linux_nat_terminal_inferior (struct target_ops *self)

delete_file_handler (input_fd);
async_terminal_is_ours = 0;
+
+ /* Discard any local stdin events that occur while an attached inferior is
+ (synchronously) running. These events would otherwise eventually get
+ passed to the command line once GDB regains control. This is problematic
+ because submitting an empty command line causes the previous command to
+ run again, so accidentally typing "continue\n\n" would perform "continue"
+ twice. By discarding local stdin events while an attached inferior is
+ active, typing "continue\n\n" will only perform "continue" once because
+ the 2nd "\n" will now get discarded, saving some headache for the clumsy
+ user.
+
+ This event handler will get replaced by the regular stdin event handler
+ will in the next call to target_terminal_ours(). */
+
+ if (current_inferior ()->attach_flag
+ && instream == stdin
+ && ISATTY (instream))
+ add_file_handler (input_fd, stdin_discard_event_handler, 0);
+
set_sigint_trap ();
}

--
2.4.2.387.gf86f31a.dirty