diff options
author | Pedro Alves <palves@redhat.com> | 2014-10-23 17:13:35 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2014-10-29 17:29:26 +0000 |
commit | d3d4baedb6d247c6372678edd15195a1a93c2c6c (patch) | |
tree | 7db1f5216dddae6dc675ee5291fc3ab3ea9ecaa1 /gdb/event-top.c | |
parent | d1e8523e40ed5094ed7d5b352ac6b0eabf9f690c (diff) | |
download | gdb-d3d4baedb6d247c6372678edd15195a1a93c2c6c.zip gdb-d3d4baedb6d247c6372678edd15195a1a93c2c6c.tar.gz gdb-d3d4baedb6d247c6372678edd15195a1a93c2c6c.tar.bz2 |
PR python/17372 - Python hangs when displaying help()
This is more of a readline/terminal issue than a Python one.
PR17372 is a regression in 7.8 caused by the fix for PR17072:
commit 0017922d0292d8c374584f6100874580659c9973
Author: Pedro Alves <palves@redhat.com>
Date: Mon Jul 14 19:55:32 2014 +0100
Background execution + pagination aborts readline/gdb
gdb_readline_wrapper_line removes the handler after a line is
processed. Usually, we'll end up re-displaying the prompt, and that
reinstalls the handler. But if the output is coming out of handling
a stop event, we don't re-display the prompt, and nothing restores the
handler. So the next input wakes up the event loop and calls into
readline, which aborts.
...
gdb/
2014-07-14 Pedro Alves <palves@redhat.com>
PR gdb/17072
* top.c (gdb_readline_wrapper_line): Tweak comment.
(gdb_readline_wrapper_cleanup): If readline is enabled, reinstall
the input handler callback.
The problem is that installing the input handler callback also preps
the terminal, putting it in raw mode and with echo disabled, which is
bad if we're going to call a command that assumes cooked/canonical
mode, and echo enabled, like in the case of the PR, Python's
interactive shell. Another example I came up with that doesn't depend
on Python is starting a subshell with "(gdb) shell /bin/sh" from a
multi-line command. Tests covering both these examples are added.
The fix is to revert the original fix for PR gdb/17072, and instead
restore the callback handler after processing an asynchronous target
event.
Furthermore, calling rl_callback_handler_install when we already have
some input in readline's line buffer discards that input, which is
obviously a bad thing to do while the user is typing. No specific
test is added for that, because I first tried calling it even if the
callback handler was still installed and that resulted in hundreds of
failures in the testsuite.
gdb/
2014-10-29 Pedro Alves <palves@redhat.com>
PR python/17372
* event-top.c (change_line_handler): Call
gdb_rl_callback_handler_remove instead of
rl_callback_handler_remove.
(callback_handler_installed): New global.
(gdb_rl_callback_handler_remove, gdb_rl_callback_handler_install)
(gdb_rl_callback_handler_reinstall): New functions.
(display_gdb_prompt): Call gdb_rl_callback_handler_remove and
gdb_rl_callback_handler_install instead of
rl_callback_handler_remove and rl_callback_handler_install.
(gdb_disable_readline): Call gdb_rl_callback_handler_remove
instead of rl_callback_handler_remove.
* event-top.h (gdb_rl_callback_handler_remove)
(gdb_rl_callback_handler_install)
(gdb_rl_callback_handler_reinstall): New declarations.
* infrun.c (reinstall_readline_callback_handler_cleanup): New
cleanup function.
(fetch_inferior_event): Install it.
* top.c (gdb_readline_wrapper_line) Call
gdb_rl_callback_handler_remove instead of
rl_callback_handler_remove.
(gdb_readline_wrapper_cleanup): Don't call
rl_callback_handler_install.
gdb/testsuite/
2014-10-29 Pedro Alves <palves@redhat.com>
PR python/17372
* gdb.python/python.exp: Test a multi-line command that spawns
interactive Python.
* gdb.base/multi-line-starts-subshell.exp: New file.
Diffstat (limited to 'gdb/event-top.c')
-rw-r--r-- | gdb/event-top.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/gdb/event-top.c b/gdb/event-top.c index f539733..282c0fe 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -205,7 +205,7 @@ change_line_handler (void) else { /* Turn off editing by using gdb_readline2. */ - rl_callback_handler_remove (); + gdb_rl_callback_handler_remove (); call_readline = gdb_readline2; /* Set up the command handler as well, in case we are called as @@ -214,6 +214,57 @@ change_line_handler (void) } } +/* The functions below are wrappers for rl_callback_handler_remove and + rl_callback_handler_install that keep track of whether the callback + handler is installed in readline. This is necessary because after + handling a target event of a background execution command, we may + need to reinstall the callback handler if it was removed due to a + secondary prompt. See gdb_readline_wrapper_line. We don't + unconditionally install the handler for every target event because + that also clears the line buffer, thus installing it while the user + is typing would lose input. */ + +/* Whether we've registered a callback handler with readline. */ +static int callback_handler_installed; + +/* See event-top.h, and above. */ + +void +gdb_rl_callback_handler_remove (void) +{ + rl_callback_handler_remove (); + callback_handler_installed = 0; +} + +/* See event-top.h, and above. Note this wrapper doesn't have an + actual callback parameter because we always install + INPUT_HANDLER. */ + +void +gdb_rl_callback_handler_install (const char *prompt) +{ + /* Calling rl_callback_handler_install resets readline's input + buffer. Calling this when we were already processing input + therefore loses input. */ + gdb_assert (!callback_handler_installed); + + rl_callback_handler_install (prompt, input_handler); + callback_handler_installed = 1; +} + +/* See event-top.h, and above. */ + +void +gdb_rl_callback_handler_reinstall (void) +{ + if (!callback_handler_installed) + { + /* Passing NULL as prompt argument tells readline to not display + a prompt. */ + gdb_rl_callback_handler_install (NULL); + } +} + /* Displays the prompt. If the argument NEW_PROMPT is NULL, the prompt that is displayed is the current top level prompt. Otherwise, it displays whatever NEW_PROMPT is as a local/secondary @@ -267,7 +318,7 @@ display_gdb_prompt (char *new_prompt) the above two functions. Calling rl_callback_handler_remove(), does the job. */ - rl_callback_handler_remove (); + gdb_rl_callback_handler_remove (); do_cleanups (old_chain); return; } @@ -282,8 +333,8 @@ display_gdb_prompt (char *new_prompt) if (async_command_editing_p) { - rl_callback_handler_remove (); - rl_callback_handler_install (actual_gdb_prompt, input_handler); + gdb_rl_callback_handler_remove (); + gdb_rl_callback_handler_install (actual_gdb_prompt); } /* new_prompt at this point can be the top of the stack or the one passed in. It can't be NULL. */ @@ -1040,6 +1091,6 @@ gdb_disable_readline (void) gdb_stdtargerr = NULL; #endif - rl_callback_handler_remove (); + gdb_rl_callback_handler_remove (); delete_file_handler (input_fd); } |