aboutsummaryrefslogtreecommitdiff
path: root/gdb/event-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:53:40 +0100
commit5cc3ce8b5fffa7413557b7e071d8471ae6e2fc88 (patch)
tree2ef4aa7b8103afe6c707205fb0f06328dc5222c9 /gdb/event-top.c
parent00340e1b916fa2d040439b101c220fae3c5834fa (diff)
downloadgdb-5cc3ce8b5fffa7413557b7e071d8471ae6e2fc88.zip
gdb-5cc3ce8b5fffa7413557b7e071d8471ae6e2fc88.tar.gz
gdb-5cc3ce8b5fffa7413557b7e071d8471ae6e2fc88.tar.bz2
Fix signal handler/event-loop races
GDB's core signal handling suffers from a classical signal handler / mainline code race: int gdb_do_one_event (void) { ... /* First let's see if there are any asynchronous signal handlers that are ready. These would be the result of invoking any of the signal handlers. */ if (invoke_async_signal_handlers ()) return 1; ... /* Block waiting for a new event. (...). */ if (gdb_wait_for_event (1) < 0) return -1; ... } If a signal is delivered while gdb is blocked in the poll/select inside gdb_wait_for_event, then the select/poll breaks with EINTR, we'll loop back around and call invoke_async_signal_handlers. However, if the signal handler runs between invoke_async_signal_handlers and gdb_wait_for_event, gdb_wait_for_event will block, until the next unrelated event... The fix is to a struct serial_event, and register it in the set of files that select/poll in gdb_wait_for_event waits on. The signal handlers that defer work to invoke_async_signal_handlers call mark_async_signal_handler, which is adjusted to also set the new serial event in addition to setting a flag, and is thus now is garanteed to immediately unblock the next gdb_select/poll call, up until invoke_async_signal_handlers is called and the event is cleared. gdb/ChangeLog: 2016-04-12 Pedro Alves <palves@redhat.com> * event-loop.c: Include "ser-event.h". (async_signal_handlers_serial_event): New global. (async_signals_handler, initialize_async_signal_handlers): New functions. (mark_async_signal_handler): Set async_signal_handlers_serial_event. (invoke_async_signal_handlers): Clear async_signal_handlers_serial_event. * event-top.c (async_init_signals): Call initialize_async_signal_handlers.
Diffstat (limited to 'gdb/event-top.c')
-rw-r--r--gdb/event-top.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/gdb/event-top.c b/gdb/event-top.c
index a119fe9..2f0a758 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -748,6 +748,8 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
void
async_init_signals (void)
{
+ initialize_async_signal_handlers ();
+
signal (SIGINT, handle_sigint);
sigint_token =
create_async_signal_handler (async_request_quit, NULL);