X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fevent-top.c;h=73771894c9a7afaee400f01c6fd14831ec886b49;hb=eb4c3f4aaae2ee1b27c210e951260a7e699133b4;hp=41d3aacead4fcc5d85c1a04b617591b66c8c2529;hpb=048094accce2110432bf7d44c34acc17865cf85a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/event-top.c b/gdb/event-top.c index 41d3aacead..73771894c9 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -1,6 +1,6 @@ /* Top level stuff for GDB, the GNU debugger. - Copyright (C) 1999-2016 Free Software Foundation, Inc. + Copyright (C) 1999-2017 Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. @@ -48,10 +48,7 @@ /* readline defines this. */ #undef savestring -static void rl_callback_read_char_wrapper (gdb_client_data client_data); -static void command_line_handler (char *rl); -static void change_line_handler (void); -static char *top_level_prompt (void); +static std::string top_level_prompt (); /* Signal handlers. */ #ifdef SIGQUIT @@ -71,33 +68,15 @@ static void async_do_nothing (gdb_client_data); static void async_disconnect (gdb_client_data); #endif static void async_float_handler (gdb_client_data); -#ifdef STOP_SIGNAL -static void async_stop_sig (gdb_client_data); +#ifdef SIGTSTP +static void async_sigtstp_handler (gdb_client_data); #endif static void async_sigterm_handler (gdb_client_data arg); -/* Readline offers an alternate interface, via callback - functions. These are all included in the file callback.c in the - readline distribution. This file provides (mainly) a function, which - the event loop uses as callback (i.e. event handler) whenever an event - is detected on the standard input file descriptor. - readline_callback_read_char is called (by the GDB event loop) whenever - there is a new character ready on the input stream. This function - incrementally builds a buffer internal to readline where it - accumulates the line read up to the point of invocation. In the - special case in which the character read is newline, the function - invokes a GDB supplied callback routine, which does the processing of - a full command line. This latter routine is the asynchronous analog - of the old command_line_input in gdb. Instead of invoking (and waiting - for) readline to read the command line and pass it back to - command_loop for processing, the new command_line_handler function has - the command line already available as its parameter. INPUT_HANDLER is - to be set to the function that readline will invoke when a complete - line of input is ready. CALL_READLINE is to be set to the function - that readline offers as callback to the event_loop. */ - -void (*input_handler) (char *); -void (*call_readline) (gdb_client_data); +/* Instead of invoking (and waiting for) readline to read the command + line and pass it back for processing, we use readline's alternate + interface, via callback functions, so that the event loop can react + to other event sources while we wait for input. */ /* Important variables for the event loop. */ @@ -107,16 +86,12 @@ void (*call_readline) (gdb_client_data); ezannoni: as of 1999-04-29 I expect that this variable will not be used after gdb is changed to use the event loop as default engine, and event-top.c is merged into top.c. */ -int async_command_editing_p; +int set_editing_cmd_var; /* This is used to display the notification of the completion of an asynchronous execution command. */ int exec_done_display_p = 0; -/* This is the file descriptor for the input stream that GDB uses to - read commands from. */ -int input_fd; - /* Used by the stdin event handler to compensate for missed stdin events. Setting this to a non-zero value inside an stdin callback makes the callback run again. */ @@ -136,38 +111,122 @@ static struct async_signal_handler *sighup_token; static struct async_signal_handler *sigquit_token; #endif static struct async_signal_handler *sigfpe_token; -#ifdef STOP_SIGNAL +#ifdef SIGTSTP static struct async_signal_handler *sigtstp_token; #endif static struct async_signal_handler *async_sigterm_token; -/* This hook is called by rl_callback_read_char_wrapper after each +/* This hook is called by gdb_rl_callback_read_char_wrapper after each character is processed. */ void (*after_char_processing_hook) (void); -/* Wrapper function for calling into the readline library. The event - loop expects the callback function to have a paramter, while - readline expects none. */ +/* Wrapper function for calling into the readline library. This takes + care of a couple things: + + - The event loop expects the callback function to have a parameter, + while readline expects none. + + - Propagation of GDB exceptions/errors thrown from INPUT_HANDLER + across readline requires special handling. + + On the exceptions issue: + + DWARF-based unwinding cannot cross code built without -fexceptions. + Any exception that tries to propagate through such code will fail + and the result is a call to std::terminate. While some ABIs, such + as x86-64, require all code to be built with exception tables, + others don't. + + This is a problem when GDB calls some non-EH-aware C library code, + that calls into GDB again through a callback, and that GDB callback + code throws a C++ exception. Turns out this is exactly what + happens with GDB's readline callback. + + In such cases, we must catch and save any C++ exception that might + be thrown from the GDB callback before returning to the + non-EH-aware code. When the non-EH-aware function itself returns + back to GDB, we then rethrow the original C++ exception. + + In the readline case however, the right thing to do is to longjmp + out of the callback, rather than do a normal return -- there's no + way for the callback to return to readline an indication that an + error happened, so a normal return would have rl_callback_read_char + potentially continue processing further input, redisplay the + prompt, etc. Instead of raw setjmp/longjmp however, we use our + sjlj-based TRY/CATCH mechanism, which knows to handle multiple + levels of active setjmp/longjmp frames, needed in order to handle + the readline callback recursing, as happens with e.g., secondary + prompts / queries, through gdb_readline_wrapper. This must be + noexcept in order to avoid problems with mixing sjlj and + (sjlj-based) C++ exceptions. */ + +static struct gdb_exception +gdb_rl_callback_read_char_wrapper_noexcept () noexcept +{ + struct gdb_exception gdb_expt = exception_none; + + /* C++ exceptions can't normally be thrown across readline (unless + it is built with -fexceptions, but it won't by default on many + ABIs). So we instead wrap the readline call with a sjlj-based + TRY/CATCH, and rethrow the GDB exception once back in GDB. */ + TRY_SJLJ + { + rl_callback_read_char (); + if (after_char_processing_hook) + (*after_char_processing_hook) (); + } + CATCH_SJLJ (ex, RETURN_MASK_ALL) + { + gdb_expt = ex; + } + END_CATCH_SJLJ + + return gdb_expt; +} + static void -rl_callback_read_char_wrapper (gdb_client_data client_data) +gdb_rl_callback_read_char_wrapper (gdb_client_data client_data) { - rl_callback_read_char (); - if (after_char_processing_hook) - (*after_char_processing_hook) (); + struct gdb_exception gdb_expt + = gdb_rl_callback_read_char_wrapper_noexcept (); + + /* Rethrow using the normal EH mechanism. */ + if (gdb_expt.reason < 0) + throw_exception (gdb_expt); } -/* Initialize all the necessary variables, start the event loop, - register readline, and stdin, start the loop. The DATA is the - interpreter data cookie, ignored for now. */ +/* GDB's readline callback handler. Calls the current INPUT_HANDLER, + and propagates GDB exceptions/errors thrown from INPUT_HANDLER back + across readline. See gdb_rl_callback_read_char_wrapper. This must + be noexcept in order to avoid problems with mixing sjlj and + (sjlj-based) C++ exceptions. */ -void -cli_command_loop (void *data) +static void +gdb_rl_callback_handler (char *rl) noexcept { - display_gdb_prompt (0); + struct gdb_exception gdb_rl_expt = exception_none; + struct ui *ui = current_ui; - /* Now it's time to start the event loop. */ - start_event_loop (); + TRY + { + ui->input_handler (rl); + } + CATCH (ex, RETURN_MASK_ALL) + { + gdb_rl_expt = ex; + } + END_CATCH + + /* If we caught a GDB exception, longjmp out of the readline + callback. There's no other way for the callback to signal to + readline that an error happened. A normal return would have + readline potentially continue processing further input, redisplay + the prompt, etc. (This is what GDB historically did when it was + a C program.) Note that since we're long jumping, local variable + dtors are NOT run automatically. */ + if (gdb_rl_expt.reason < 0) + throw_exception_sjlj (gdb_rl_expt); } /* Change the function to be invoked every time there is a character @@ -175,32 +234,45 @@ cli_command_loop (void *data) therefore bypassing readline, and letting gdb handle the input itself, via gdb_readline_no_editing_callback. Also it is used in the opposite case in which the user sets editing on again, by - restoring readline handling of the input. */ -static void -change_line_handler (void) + restoring readline handling of the input. + + NOTE: this operates on input_fd, not instream. If we are reading + commands from a file, instream will point to the file. However, we + always read commands from a file with editing off. This means that + the 'set editing on/off' will have effect only on the interactive + session. */ + +void +change_line_handler (int editing) { - /* NOTE: this operates on input_fd, not instream. If we are reading - commands from a file, instream will point to the file. However in - async mode, we always read commands from a file with editing - off. This means that the 'set editing on/off' will have effect - only on the interactive session. */ + struct ui *ui = current_ui; + + /* We can only have one instance of readline, so we only allow + editing on the main UI. */ + if (ui != main_ui) + return; - if (async_command_editing_p) + /* Don't try enabling editing if the interpreter doesn't support it + (e.g., MI). */ + if (!interp_supports_command_editing (top_level_interpreter ()) + || !interp_supports_command_editing (command_interp ())) + return; + + if (editing) { + gdb_assert (ui == main_ui); + /* Turn on editing by using readline. */ - call_readline = rl_callback_read_char_wrapper; - input_handler = command_line_handler; + ui->call_readline = gdb_rl_callback_read_char_wrapper; } else { /* Turn off editing by using gdb_readline_no_editing_callback. */ - gdb_rl_callback_handler_remove (); - call_readline = gdb_readline_no_editing_callback; - - /* Set up the command handler as well, in case we are called as - first thing from .gdbinit. */ - input_handler = command_line_handler; + if (ui->command_editing) + gdb_rl_callback_handler_remove (); + ui->call_readline = gdb_readline_no_editing_callback; } + ui->command_editing = editing; } /* The functions below are wrappers for rl_callback_handler_remove and @@ -221,6 +293,8 @@ static int callback_handler_installed; void gdb_rl_callback_handler_remove (void) { + gdb_assert (current_ui == main_ui); + rl_callback_handler_remove (); callback_handler_installed = 0; } @@ -232,12 +306,14 @@ gdb_rl_callback_handler_remove (void) void gdb_rl_callback_handler_install (const char *prompt) { + gdb_assert (current_ui == main_ui); + /* 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); + rl_callback_handler_install (prompt, gdb_rl_callback_handler); callback_handler_installed = 1; } @@ -246,6 +322,8 @@ gdb_rl_callback_handler_install (const char *prompt) void gdb_rl_callback_handler_reinstall (void) { + gdb_assert (current_ui == main_ui); + if (!callback_handler_installed) { /* Passing NULL as prompt argument tells readline to not display @@ -274,22 +352,23 @@ gdb_rl_callback_handler_reinstall (void) void display_gdb_prompt (const char *new_prompt) { - char *actual_gdb_prompt = NULL; - struct cleanup *old_chain; + std::string actual_gdb_prompt; annotate_display_prompt (); /* Reset the nesting depth used when trace-commands is set. */ reset_command_nest_depth (); - old_chain = make_cleanup (free_current_contents, &actual_gdb_prompt); - /* Do not call the python hook on an explicit prompt change as passed to this function, as this forms a secondary/local prompt, IE, displayed but not set. */ if (! new_prompt) { - if (sync_execution) + struct ui *ui = current_ui; + + if (ui->prompt_state == PROMPTED) + internal_error (__FILE__, __LINE__, _("double prompt")); + else if (ui->prompt_state == PROMPT_BLOCKED) { /* This is to trick readline into not trying to display the prompt. Even though we display the prompt using this @@ -307,23 +386,24 @@ display_gdb_prompt (const char *new_prompt) the above two functions. Calling rl_callback_handler_remove(), does the job. */ - gdb_rl_callback_handler_remove (); - do_cleanups (old_chain); + if (current_ui->command_editing) + gdb_rl_callback_handler_remove (); return; } - else + else if (ui->prompt_state == PROMPT_NEEDED) { /* Display the top level prompt. */ actual_gdb_prompt = top_level_prompt (); + ui->prompt_state = PROMPTED; } } else - actual_gdb_prompt = xstrdup (new_prompt); + actual_gdb_prompt = new_prompt; - if (async_command_editing_p) + if (current_ui->command_editing) { gdb_rl_callback_handler_remove (); - gdb_rl_callback_handler_install (actual_gdb_prompt); + gdb_rl_callback_handler_install (actual_gdb_prompt.c_str ()); } /* new_prompt at this point can be the top of the stack or the one passed in. It can't be NULL. */ @@ -332,19 +412,16 @@ display_gdb_prompt (const char *new_prompt) /* Don't use a _filtered function here. It causes the assumed character position to be off, since the newline we read from the user is not accounted for. */ - fputs_unfiltered (actual_gdb_prompt, gdb_stdout); + fputs_unfiltered (actual_gdb_prompt.c_str (), gdb_stdout); gdb_flush (gdb_stdout); } - - do_cleanups (old_chain); } /* Return the top level prompt, as specified by "set prompt", possibly overriden by the python gdb.prompt_hook hook, and then composed - with the prompt prefix and suffix (annotations). The caller is - responsible for freeing the returned string. */ + with the prompt prefix and suffix (annotations). */ -static char * +static std::string top_level_prompt (void) { char *prompt; @@ -364,28 +441,25 @@ top_level_prompt (void) beginning. */ const char suffix[] = "\n\032\032prompt\n"; - return concat (prefix, prompt, suffix, NULL); + return std::string (prefix) + prompt + suffix; } - return xstrdup (prompt); + return prompt; } -/* Get a pointer to the command line buffer. This is used to +/* See top.h. */ + +struct ui *main_ui; +struct ui *current_ui; +struct ui *ui_list; + +/* Get a pointer to the current UI's line buffer. This is used to construct a whole line of input from partial input. */ static struct buffer * get_command_line_buffer (void) { - static struct buffer line_buffer; - static int line_buffer_initialized; - - if (!line_buffer_initialized) - { - buffer_init (&line_buffer); - line_buffer_initialized = 1; - } - - return &line_buffer; + return ¤t_ui->line_buffer; } /* When there is an event ready on the stdin file descriptor, instead @@ -396,32 +470,66 @@ get_command_line_buffer (void) void stdin_event_handler (int error, gdb_client_data client_data) { + struct ui *ui = (struct ui *) client_data; + if (error) { - printf_unfiltered (_("error detected on stdin\n")); - delete_file_handler (input_fd); - /* If stdin died, we may as well kill gdb. */ - quit_command ((char *) 0, stdin == instream); + /* Switch to the main UI, so diagnostics always go there. */ + current_ui = main_ui; + + delete_file_handler (ui->input_fd); + if (main_ui == ui) + { + /* If stdin died, we may as well kill gdb. */ + printf_unfiltered (_("error detected on stdin\n")); + quit_command ((char *) 0, 0); + } + else + { + /* Simply delete the UI. */ + delete ui; + } } else { - /* This makes sure a ^C immediately followed by further input is - always processed in that order. E.g,. with input like - "^Cprint 1\n", the SIGINT handler runs, marks the async signal - handler, and then select/poll may return with stdin ready, - instead of -1/EINTR. The - gdb.base/double-prompt-target-event-error.exp test exercises - this. */ + /* Switch to the UI whose input descriptor woke up the event + loop. */ + current_ui = ui; + + /* This makes sure a ^C immediately followed by further input is + always processed in that order. E.g,. with input like + "^Cprint 1\n", the SIGINT handler runs, marks the async + signal handler, and then select/poll may return with stdin + ready, instead of -1/EINTR. The + gdb.base/double-prompt-target-event-error.exp test exercises + this. */ QUIT; do { call_stdin_event_handler_again_p = 0; - (*call_readline) (client_data); - } while (call_stdin_event_handler_again_p != 0); + ui->call_readline (client_data); + } + while (call_stdin_event_handler_again_p != 0); } } +/* See top.h. */ + +void +ui_register_input_event_handler (struct ui *ui) +{ + add_file_handler (ui->input_fd, stdin_event_handler, ui); +} + +/* See top.h. */ + +void +ui_unregister_input_event_handler (struct ui *ui) +{ + delete_file_handler (ui->input_fd); +} + /* 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. */ @@ -429,14 +537,13 @@ stdin_event_handler (int error, gdb_client_data client_data) void async_enable_stdin (void) { - if (sync_execution) + struct ui *ui = current_ui; + + if (ui->prompt_state == PROMPT_BLOCKED) { - /* See NOTE in async_disable_stdin(). */ - /* FIXME: cagney/1999-09-27: Call this before clearing - sync_execution. Current target_terminal_ours() implementations - check for sync_execution before switching the terminal. */ - target_terminal_ours (); - sync_execution = 0; + target_terminal::ours (); + ui_register_input_event_handler (ui); + ui->prompt_state = PROMPT_NEEDED; } } @@ -446,7 +553,10 @@ async_enable_stdin (void) void async_disable_stdin (void) { - sync_execution = 1; + struct ui *ui = current_ui; + + ui->prompt_state = PROMPT_BLOCKED; + delete_file_handler (ui->input_fd); } @@ -457,26 +567,24 @@ async_disable_stdin (void) void command_handler (char *command) { - struct cleanup *stat_chain; + struct ui *ui = current_ui; char *c; - if (instream == stdin) + if (ui->instream == ui->stdin_stream) reinitialize_more_filter (); - stat_chain = make_command_stats_cleanup (1); + scoped_command_stats stat_reporter (true); /* Do not execute commented lines. */ for (c = command; *c == ' ' || *c == '\t'; c++) ; if (c[0] != '#') { - execute_command (command, instream == stdin); + execute_command (command, ui->instream == ui->stdin_stream); /* Do any commands attached to breakpoint we stopped at. */ bpstat_do_actions (); } - - do_cleanups (stat_chain); } /* Append RL, an input line returned by readline or one of its @@ -535,8 +643,10 @@ command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl) char * handle_line_of_input (struct buffer *cmd_line_buffer, - char *rl, int repeat, char *annotation_suffix) + char *rl, int repeat, const char *annotation_suffix) { + struct ui *ui = current_ui; + int from_tty = ui->instream == ui->stdin_stream; char *p1; char *cmd; @@ -551,7 +661,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, command, but leave ownership of memory to the buffer . */ cmd_line_buffer->used_size = 0; - if (annotation_level > 1 && instream == stdin) + if (from_tty && annotation_level > 1) { printf_unfiltered (("\n\032\032post-")); puts_unfiltered (annotation_suffix); @@ -568,8 +678,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, } /* Do history expansion if that is wished. */ - if (history_expansion_p && instream == stdin - && ISATTY (instream)) + if (history_expansion_p && from_tty && input_interactive_p (current_ui)) { char *history_value; int expanded; @@ -613,7 +722,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, and then later fetch it from the value history and remove the '#'. The kill ring is probably better, but some people are in the habit of commenting things out. */ - if (*cmd != '\0' && input_from_terminal_p ()) + if (*cmd != '\0' && from_tty && input_interactive_p (current_ui)) gdb_add_history (cmd); /* Save into global buffer if appropriate. */ @@ -639,9 +748,10 @@ void command_line_handler (char *rl) { struct buffer *line_buffer = get_command_line_buffer (); + struct ui *ui = current_ui; char *cmd; - cmd = handle_line_of_input (line_buffer, rl, instream == stdin, "prompt"); + cmd = handle_line_of_input (line_buffer, rl, 1, "prompt"); if (cmd == (char *) EOF) { /* stdin closed. The connection with the terminal is gone. @@ -649,7 +759,7 @@ command_line_handler (char *rl) hung up but GDB is still alive. In such a case, we just quit gdb killing the inferior program too. */ printf_unfiltered ("quit\n"); - execute_command ("quit", stdin == instream); + execute_command ((char *) "quit", 1); } else if (cmd == NULL) { @@ -658,8 +768,12 @@ command_line_handler (char *rl) } else { + ui->prompt_state = PROMPT_NEEDED; + command_handler (cmd); - display_gdb_prompt (0); + + if (ui->prompt_state != PROMPTED) + display_gdb_prompt (0); } } @@ -674,6 +788,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) char *result; struct buffer line_buffer; static int done_once = 0; + struct ui *ui = current_ui; buffer_init (&line_buffer); @@ -683,9 +798,9 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) stream after '\n'. If we buffer the input and fgetc drains the stream, getting stuff beyond the newline as well, a select, done afterwards will not trigger. */ - if (!done_once && !ISATTY (instream)) + if (!done_once && !ISATTY (ui->instream)) { - setbuf (instream, NULL); + setbuf (ui->instream, NULL); done_once = 1; } @@ -701,7 +816,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) { /* Read from stdin if we are executing a user defined command. This is the right thing for prompt_for_continue, at least. */ - c = fgetc (instream ? instream : stdin); + c = fgetc (ui->instream != NULL ? ui->instream : ui->stdin_stream); if (c == EOF) { @@ -713,7 +828,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) break; } xfree (buffer_finish (&line_buffer)); - (*input_handler) (0); + ui->input_handler (NULL); return; } @@ -730,7 +845,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) buffer_grow_char (&line_buffer, '\0'); result = buffer_finish (&line_buffer); - (*input_handler) (result); + ui->input_handler (result); } @@ -797,9 +912,9 @@ async_init_signals (void) sigfpe_token = create_async_signal_handler (async_float_handler, NULL); -#ifdef STOP_SIGNAL +#ifdef SIGTSTP sigtstp_token = - create_async_signal_handler (async_stop_sig, NULL); + create_async_signal_handler (async_sigtstp_handler, NULL); #endif } @@ -835,7 +950,7 @@ default_quit_handler (void) { if (check_quit_flag ()) { - if (target_terminal_is_ours ()) + if (target_terminal::is_ours ()) quit (); else target_pass_ctrlc (); @@ -845,51 +960,6 @@ default_quit_handler (void) /* See defs.h. */ quit_handler_ftype *quit_handler = default_quit_handler; -/* Data for make_cleanup_override_quit_handler. Wrap the previous - handler pointer in a data struct because it's not portable to cast - a function pointer to a data pointer, which is what make_cleanup - expects. */ -struct quit_handler_cleanup_data -{ - /* The previous quit handler. */ - quit_handler_ftype *prev_handler; -}; - -/* Cleanup call that restores the previous quit handler. */ - -static void -restore_quit_handler (void *arg) -{ - struct quit_handler_cleanup_data *data - = (struct quit_handler_cleanup_data *) arg; - - quit_handler = data->prev_handler; -} - -/* Destructor for the quit handler cleanup. */ - -static void -restore_quit_handler_dtor (void *arg) -{ - xfree (arg); -} - -/* See defs.h. */ - -struct cleanup * -make_cleanup_override_quit_handler (quit_handler_ftype *new_quit_handler) -{ - struct cleanup *old_chain; - struct quit_handler_cleanup_data *data; - - data = XNEW (struct quit_handler_cleanup_data); - data->prev_handler = quit_handler; - old_chain = make_cleanup_dtor (restore_quit_handler, data, - restore_quit_handler_dtor); - quit_handler = new_quit_handler; - return old_chain; -} - /* Handle a SIGINT. */ void @@ -901,18 +971,11 @@ handle_sigint (int sig) it may be quite a while before we get back to the event loop. So set quit_flag to 1 here. Then if QUIT is called before we get to the event loop, we will unwind as expected. */ - set_quit_flag (); - /* If immediate_quit is set, we go ahead and process the SIGINT right - away, even if we usually would defer this to the event loop. The - assumption here is that it is safe to process ^C immediately if - immediate_quit is set. If we didn't, SIGINT would be really - processed only the next time through the event loop. To get to - that point, though, the command that we want to interrupt needs to - finish first, which is unacceptable. If immediate quit is not set, - we process SIGINT the next time through the loop, which is fine. */ - gdb_call_async_signal_handler (sigint_token, immediate_quit); + /* In case nothing calls QUIT before the event loop is reached, the + event loop handles it. */ + mark_async_signal_handler (sigint_token); } /* See gdb_select.h. */ @@ -956,7 +1019,7 @@ interruptible_select (int n, static void async_sigterm_handler (gdb_client_data arg) { - quit_force (NULL, stdin == instream); + quit_force (NULL, 0); } /* See defs.h. */ @@ -1049,20 +1112,19 @@ async_disconnect (gdb_client_data arg) } #endif -#ifdef STOP_SIGNAL +#ifdef SIGTSTP void -handle_stop_sig (int sig) +handle_sigtstp (int sig) { mark_async_signal_handler (sigtstp_token); - signal (sig, handle_stop_sig); + signal (sig, handle_sigtstp); } static void -async_stop_sig (gdb_client_data arg) +async_sigtstp_handler (gdb_client_data arg) { char *prompt = get_prompt (); -#if STOP_SIGNAL == SIGTSTP signal (SIGTSTP, SIG_DFL); #if HAVE_SIGPROCMASK { @@ -1075,10 +1137,7 @@ async_stop_sig (gdb_client_data arg) sigsetmask (0); #endif raise (SIGTSTP); - signal (SIGTSTP, handle_stop_sig); -#else - signal (STOP_SIGNAL, handle_stop_sig); -#endif + signal (SIGTSTP, handle_sigtstp); printf_unfiltered ("%s", prompt); gdb_flush (gdb_stdout); @@ -1086,7 +1145,7 @@ async_stop_sig (gdb_client_data arg) nothing. */ dont_repeat (); } -#endif /* STOP_SIGNAL */ +#endif /* SIGTSTP */ /* Tell the event loop what to do if SIGFPE is received. See event-signal.c. */ @@ -1107,78 +1166,66 @@ async_float_handler (gdb_client_data arg) } -/* Called by do_setshow_command. */ -void -set_async_editing_command (char *args, int from_tty, - struct cmd_list_element *c) -{ - change_line_handler (); -} - /* Set things up for readline to be invoked via the alternate - interface, i.e. via a callback function (rl_callback_read_char), - and hook up instream to the event loop. */ + interface, i.e. via a callback function + (gdb_rl_callback_read_char), and hook up instream to the event + loop. */ + void -gdb_setup_readline (void) +gdb_setup_readline (int editing) { + struct ui *ui = current_ui; + /* This function is a noop for the sync case. The assumption is that the sync setup is ALL done in gdb_init, and we would only mess it up here. The sync stuff should really go away over time. */ if (!batch_silent) - gdb_stdout = stdio_fileopen (stdout); - gdb_stderr = stderr_fileopen (); + gdb_stdout = new stdio_file (ui->outstream); + gdb_stderr = new stderr_file (ui->errstream); gdb_stdlog = gdb_stderr; /* for moment */ gdb_stdtarg = gdb_stderr; /* for moment */ gdb_stdtargerr = gdb_stderr; /* for moment */ - /* If the input stream is connected to a terminal, turn on - editing. */ - if (ISATTY (instream)) + /* If the input stream is connected to a terminal, turn on editing. + However, that is only allowed on the main UI, as we can only have + one instance of readline. */ + if (ISATTY (ui->instream) && editing && ui == main_ui) { /* Tell gdb that we will be using the readline library. This could be overwritten by a command in .gdbinit like 'set editing on' or 'off'. */ - async_command_editing_p = 1; - + ui->command_editing = 1; + /* When a character is detected on instream by select or poll, readline will be invoked via this callback function. */ - call_readline = rl_callback_read_char_wrapper; + ui->call_readline = gdb_rl_callback_read_char_wrapper; + + /* Tell readline to use the same input stream that gdb uses. */ + rl_instream = ui->instream; } else { - async_command_editing_p = 0; - call_readline = gdb_readline_no_editing_callback; + ui->command_editing = 0; + ui->call_readline = gdb_readline_no_editing_callback; } - - /* When readline has read an end-of-line character, it passes the - complete line to gdb for processing; command_line_handler is the - function that does this. */ - input_handler = command_line_handler; - - /* Tell readline to use the same input stream that gdb uses. */ - rl_instream = instream; - - /* Get a file descriptor for the input stream, so that we can - register it with the event loop. */ - input_fd = fileno (instream); - - /* Now we need to create the event sources for the input file - descriptor. */ - /* At this point in time, this is the only event source that we - register with the even loop. Another source is going to be the - target program (inferior), but that must be registered only when - it actually exists (I.e. after we say 'run' or after we connect - to a remote target. */ - add_file_handler (input_fd, stdin_event_handler, 0); + + /* Now create the event source for this UI's input file descriptor. + Another source is going to be the target program (inferior), but + that must be registered only when it actually exists (I.e. after + we say 'run' or after we connect to a remote target. */ + ui_register_input_event_handler (ui); } /* Disable command input through the standard CLI channels. Used in the suspend proc for interpreters that use the standard gdb readline interface, like the cli & the mi. */ + void gdb_disable_readline (void) { + struct ui *ui = current_ui; + /* FIXME - It is too heavyweight to delete and remake these every time you run an interpreter that needs readline. It is probably better to have the interpreters cache these, which in turn means @@ -1192,6 +1239,7 @@ gdb_disable_readline (void) gdb_stdtargerr = NULL; #endif - gdb_rl_callback_handler_remove (); - delete_file_handler (input_fd); + if (ui->command_editing) + gdb_rl_callback_handler_remove (); + delete_file_handler (ui->input_fd); }