aboutsummaryrefslogtreecommitdiff
path: root/gdb/top.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-04-12 16:49:30 +0100
committerPedro Alves <palves@redhat.com>2016-04-12 16:54:03 +0100
commitf0881b37b6734328118a5683e1e18f65a8987c89 (patch)
tree107155131f2b8453e41bf9d6b83d116523585956 /gdb/top.c
parent5cc3ce8b5fffa7413557b7e071d8471ae6e2fc88 (diff)
downloadgdb-f0881b37b6734328118a5683e1e18f65a8987c89.zip
gdb-f0881b37b6734328118a5683e1e18f65a8987c89.tar.gz
gdb-f0881b37b6734328118a5683e1e18f65a8987c89.tar.bz2
Introduce interruptible_select
We have places where we call a blocking gdb_select expecting that a Ctrl-C will unblock it. However, if the Ctrl-C is pressed just before gdb_select, the SIGINT handler runs before gdb_select, and thus gdb_select won't return. For example gdb_readline_no_editing: QUIT; /* Wait until at least one byte of data is available. Control-C can interrupt gdb_select, but not fgetc. */ FD_ZERO (&readfds); FD_SET (fd, &readfds); if (gdb_select (fd + 1, &readfds, NULL, NULL, NULL) == -1) and stdio_file_read: /* For the benefit of Windows, call gdb_select before reading from the file. Wait until at least one byte of data is available. Control-C can interrupt gdb_select, but not read. */ { fd_set readfds; FD_ZERO (&readfds); FD_SET (stdio->fd, &readfds); if (gdb_select (stdio->fd + 1, &readfds, NULL, NULL, NULL) == -1) return -1; } return read (stdio->fd, buf, length_buf); This is a race classically fixed with either the self-pipe trick, or by blocking SIGINT and then using pselect instead of select. Blocking SIGINT most of the time would mean that check_quit_flag (and thus QUIT) would need to do a syscall every time it is called, which sounds best avoided, since QUIT is called in many loops. Thus we take the self-pipe trick route (wrapped in a serial event). Instead of having all places that need this manually add an extra file descriptor to the set of gdb_select's watched file descriptors, we introduce a wrapper, interruptible_select, that does that. The Windows version of gdb_select actually does not suffer from this, because mingw-hdep.c:gdb_call_async_signal_handler sets a Windows event that gdb_select always waits on. So this patch can be seen as generalization of that technique. We can't remove that extra event from mingw-hdep.c until we get rid of immediate_quit though. gdb/ChangeLog: 2016-04-12 Pedro Alves <palves@redhat.com> * defs.h: Extend QUIT-related comments to mention interruptible_select. (quit_serial_event_set, quit_serial_event_clear): Declare. * event-top.c: Include "ser-event.h" and "gdb_select.h". (quit_serial_event): New global. (async_init_signals): Make quit_serial_event. (quit_serial_event_set, quit_serial_event_clear) (quit_serial_event_fd, interruptible_select): New functions. * extension.c (set_quit_flag): Set the quit serial event. (check_quit_flag): Clear the quit serial event. * gdb_select.h (interruptible_select): New declaration. * guile/scm-ports.c (ioscm_input_waiting): Use interruptible_select instead of gdb_select. * top.c (gdb_readline_no_editing): Likewise. * ui-file.c (stdio_file_read): Likewise.
Diffstat (limited to 'gdb/top.c')
-rw-r--r--gdb/top.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/gdb/top.c b/gdb/top.c
index 41ff6b2..f5ef718 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -613,10 +613,10 @@ gdb_readline_no_editing (const char *prompt)
QUIT;
/* Wait until at least one byte of data is available. Control-C
- can interrupt gdb_select, but not fgetc. */
+ can interrupt interruptible_select, but not fgetc. */
FD_ZERO (&readfds);
FD_SET (fd, &readfds);
- if (gdb_select (fd + 1, &readfds, NULL, NULL, NULL) == -1)
+ if (interruptible_select (fd + 1, &readfds, NULL, NULL, NULL) == -1)
{
if (errno == EINTR)
{