diff options
author | Pedro Alves <palves@redhat.com> | 2016-04-12 16:49:32 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2016-04-12 17:01:18 +0100 |
commit | 048094accce2110432bf7d44c34acc17865cf85a (patch) | |
tree | 3d6cf78a60d90e3f6b2f12358080096a825e8b4e /gdb/ser-unix.c | |
parent | a12ac51333cf97f4da0597d049cc694b4535e7dd (diff) | |
download | gdb-048094accce2110432bf7d44c34acc17865cf85a.zip gdb-048094accce2110432bf7d44c34acc17865cf85a.tar.gz gdb-048094accce2110432bf7d44c34acc17865cf85a.tar.bz2 |
target remote: Don't rely on immediate_quit (introduce quit handlers)
remote.c is the last user of immediate_quit. It's relied on to
immediately break the initial remote connection sync up, if the user
does Ctrl-C, assuming that was because the target isn't responding.
At that stage, since the connection isn't synced yet, disconnecting is
the only safe thing to do. This commit reworks that, to not rely on
throwing from the SIGINT signal handler.
So, this commit:
- Introduces the concept of a "quit handler". This is used to
override what does the QUIT macro do when the quit flag is set.
- Makes the "struct serial" reachar / write code call QUIT in the
partial read/write loops, so the current quit handler is invoked
whenever a serial->read_prim / serial->write_prim returns EINTR.
- Makes the "struct serial" reachar / write code call
interruptible_select instead of gdb_select, so that QUITs are
detected in a race-free manner.
- Stops remote.c from setting immediate_quit during the initial
connection.
- Instead, we install a custom quit handler whenever we're calling
into the serial code. This custom quit handler knows to immediately
throw a quit when we're in the initial connection setup, and
otherwise defer handling the quit/Ctrl-C request to later, when
we're safely out of a packet command/response sequence. This also
is what is now responsible for handling "double Ctrl-C because
target connection is stuck/wedged."
- remote.c no longer installs a specialized SIGINT handlers, and
instead re-uses the quit flag. Since we want to rely on the QUIT
macro, the SIGINT handler must also set the quit. And the easiest
is just to not install custom SIGINT handler in remote.c. Let the
standard SIGINT handler do its job of setting the quit flag.
Centralizing SIGINT handlers seems like a good thing to me, anyway.
gdb/ChangeLog:
2016-04-12 Pedro Alves <palves@redhat.com>
* defs.h (quit_handler_ftype, quit_handler)
(make_cleanup_override_quit_handler, default_quit_handler): New.
(QUIT): Adjust comments.
* event-top.c (default_quit_handler): New function.
(quit_handler): New global.
(struct quit_handler_cleanup_data): New.
(restore_quit_handler, restore_quit_handler_dtor)
(make_cleanup_override_quit_handler): New.
(async_request_quit): Call QUIT.
* remote.c (struct remote_state) <got_ctrlc_during_io>: New field.
(async_sigint_remote_twice_token, async_sigint_remote_token):
Delete.
(remote_close): Update comments.
(remote_start_remote): Don't set immediate_quit. Set starting_up
earlier.
(remote_serial_quit_handler, remote_unpush_and_throw): New
functions.
(remote_open_1): Clear got_ctrlc_during_io. Set
remote_async_terminal_ours_p unconditionally.
(async_initialize_sigint_signal_handler)
(async_handle_remote_sigint, async_handle_remote_sigint_twice)
(remote_check_pending_interrupt, async_remote_interrupt)
(async_remote_interrupt_twice)
(async_cleanup_sigint_signal_handler, ofunc)
(sync_remote_interrupt, sync_remote_interrupt_twice): Delete.
(remote_terminal_inferior, remote_terminal_ours): Remove async
checks.
(remote_wait_as): Don't install a SIGINT handler in sync mode.
(readchar, remote_serial_write): Override the quit handler with
remote_serial_quit_handler.
(getpkt_or_notif_sane_1): Don't call QUIT.
(initialize_remote_ops): Don't install
remote_check_pending_interrupt.
(_initialize_remote): Don't create async_sigint_remote_token and
async_sigint_remote_twice_token.
* ser-base.c (ser_base_wait_for): Call QUIT and use
interruptible_select.
(ser_base_write): Call QUIT.
* ser-go32.c (dos_readchar, dos_write): Call QUIT.
* ser-unix.c (wait_for): Don't use VTIME. Always take the
gdb_select path, but call QUIT and interruptible_select.
* utils.c (maybe_quit): Call the current quit handler. Don't call
target_check_pending_interrupt.
(defaulted_query, prompt_for_continue): Override the quit handler
with the default quit handler.
Diffstat (limited to 'gdb/ser-unix.c')
-rw-r--r-- | gdb/ser-unix.c | 96 |
1 files changed, 11 insertions, 85 deletions
diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index 562e98b..2e7b1b4 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -449,10 +449,7 @@ hardwire_raw (struct serial *scb) } /* Wait for input on scb, with timeout seconds. Returns 0 on success, - otherwise SERIAL_TIMEOUT or SERIAL_ERROR. - - For termio{s}, we actually just setup VTIME if necessary, and let the - timeout occur in the read() in hardwire_read(). */ + otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */ /* FIXME: cagney/1999-09-16: Don't replace this with the equivalent ser_base*() until the old TERMIOS/SGTTY/... timer code has been @@ -466,7 +463,6 @@ hardwire_raw (struct serial *scb) static int wait_for (struct serial *scb, int timeout) { -#ifdef HAVE_SGTTY while (1) { struct timeval tv; @@ -483,92 +479,22 @@ wait_for (struct serial *scb, int timeout) FD_ZERO (&readfds); FD_SET (scb->fd, &readfds); + QUIT; + if (timeout >= 0) - numfds = gdb_select (scb->fd + 1, &readfds, 0, 0, &tv); + numfds = interruptible_select (scb->fd + 1, &readfds, 0, 0, &tv); else - numfds = gdb_select (scb->fd + 1, &readfds, 0, 0, 0); + numfds = interruptible_select (scb->fd + 1, &readfds, 0, 0, 0); - if (numfds <= 0) - if (numfds == 0) - return SERIAL_TIMEOUT; - else if (errno == EINTR) - continue; - else - return SERIAL_ERROR; /* Got an error from select or poll. */ + if (numfds == -1 && errno == EINTR) + continue; + else if (numfds == -1) + return SERIAL_ERROR; + else if (numfds == 0) + return SERIAL_TIMEOUT; return 0; } -#endif /* HAVE_SGTTY */ - -#if defined HAVE_TERMIO || defined HAVE_TERMIOS - if (timeout == scb->current_timeout) - return 0; - - scb->current_timeout = timeout; - - { - struct hardwire_ttystate state; - - if (get_tty_state (scb, &state)) - fprintf_unfiltered (gdb_stderr, "get_tty_state failed: %s\n", - safe_strerror (errno)); - -#ifdef HAVE_TERMIOS - if (timeout < 0) - { - /* No timeout. */ - state.termios.c_cc[VTIME] = 0; - state.termios.c_cc[VMIN] = 1; - } - else - { - state.termios.c_cc[VMIN] = 0; - state.termios.c_cc[VTIME] = timeout * 10; - if (state.termios.c_cc[VTIME] != timeout * 10) - { - - /* If c_cc is an 8-bit signed character, we can't go - bigger than this. If it is always unsigned, we could use - 25. */ - - scb->current_timeout = 12; - state.termios.c_cc[VTIME] = scb->current_timeout * 10; - scb->timeout_remaining = timeout - scb->current_timeout; - } - } -#endif - -#ifdef HAVE_TERMIO - if (timeout < 0) - { - /* No timeout. */ - state.termio.c_cc[VTIME] = 0; - state.termio.c_cc[VMIN] = 1; - } - else - { - state.termio.c_cc[VMIN] = 0; - state.termio.c_cc[VTIME] = timeout * 10; - if (state.termio.c_cc[VTIME] != timeout * 10) - { - /* If c_cc is an 8-bit signed character, we can't go - bigger than this. If it is always unsigned, we could use - 25. */ - - scb->current_timeout = 12; - state.termio.c_cc[VTIME] = scb->current_timeout * 10; - scb->timeout_remaining = timeout - scb->current_timeout; - } - } -#endif - - if (set_tty_state (scb, &state)) - fprintf_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", - safe_strerror (errno)); - - return 0; - } -#endif /* HAVE_TERMIO || HAVE_TERMIOS */ } /* Read a character with user-specified timeout. TIMEOUT is number of |