From patchwork Fri May 6 12:34:58 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 12102 Received: (qmail 1261 invoked by alias); 6 May 2016 12:43:50 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 1120 invoked by uid 89); 6 May 2016 12:43:47 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.0 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=wished, History X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 06 May 2016 12:43:15 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 81DF4C04B32D for ; Fri, 6 May 2016 12:35:31 +0000 (UTC) Received: from cascais.lan (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u46CZ5IP017259 for ; Fri, 6 May 2016 08:35:30 -0400 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH v3 28/34] Make stdin be per UI Date: Fri, 6 May 2016 13:34:58 +0100 Message-Id: <1462538104-19109-29-git-send-email-palves@redhat.com> In-Reply-To: <1462538104-19109-1-git-send-email-palves@redhat.com> References: <1462538104-19109-1-git-send-email-palves@redhat.com> This commit makes each UI have its own "stdin" stream pointer. This is used to determine whether the "from_tty" argument to execute_command, etc. should be true. Related, this commit makes input_from_terminal_p take an UI parameter, and then avoids the gdb_has_a_terminal in it. gdb_has_a_terminal only returns info on gdb's own main/primary terminal (the real stdin). However, the places that call input_from_terminal_p really want to know is whether the command came from an interactive tty. This patch thus renames input_from_terminal_p to input_interactive_p for clarity, and then makes input_interactive_p check for "set interactive" itself, along with ISATTY, instead of calling gdb_has_a_terminal. Actually, quit_force wants to call input_interactive_p _after_ stdin is closed, we can't call ISATTY that late. So instead we save the result of ISATTY in a field of the UI. gdb/ChangeLog: yyyy-mm-dd Pedro Alves * cli/cli-script.c (read_next_line): Adjust to per-UI stdin. (read_command_lines): Use input_interactive_p instead of input_from_terminal_p. * defs.h (struct ui): Forward declare. (input_from_terminal_p): Rename to ... (input_interactive_p): ... this. * event-top.c (stdin_event_handler): Pass 0 as from_tty argument to quit_command. (command_handler): Adjust to per-UI stdin. (handle_line_of_input): Adjust to per-UI stdin and use input_interactive_p instead of ISATTY and input_from_terminal_p. (gdb_readline_no_editing_callback): Adjust to per-UI stdin. (command_line_handler): Always pass true as "from_tty" parameter of handle_line_of_input and execute_command. (async_sigterm_handler): Pass 0 as from_tty argument to quit_command. * inflow.c (interactive_mode, show_interactive_mode): Moved to ... (gdb_has_a_terminal): Don't check interactive_mode here. (_initialize_inflow): Don't install "set interactive-mode" here. * main.c (captured_command_loop): Adjust to per-UI stdin. * mi/mi-interp.c (mi_execute_command_wrapper): Adjust to per-UI stdin. * top.c (new_ui): Save the stdin stream and whether it's a tty. (dont_repeat): Adjust to per-UI stdin. (command_line_input): Adjust to per-UI stdin and to use input_interactive_p. (quit_force): Write history if any UI supports interactive input. (interactive_mode, show_interactive_mode): Move here, from inflow.c. (input_from_terminal_p): Rename to ... (input_interactive_p): ... this, and check the "interactive_mode" global instead of calling gdb_has_a_terminal. (_initialize_top): Install "set interactive-mode" here. * top.h (struct ui) : New fields. * utils.c (quit): Pass 0 as from_tty argument to quit_force. (defaulted_query): Adjust to per-UI stdin and to use input_interactive_p. --- gdb/cli/cli-script.c | 10 +++--- gdb/defs.h | 4 ++- gdb/event-top.c | 23 +++++++------ gdb/inflow.c | 35 -------------------- gdb/main.c | 2 +- gdb/mi/mi-interp.c | 2 +- gdb/top.c | 93 +++++++++++++++++++++++++++++++++++++++------------- gdb/top.h | 8 +++++ gdb/utils.c | 5 +-- 9 files changed, 103 insertions(+), 79 deletions(-) diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 0507c55..579d0a4 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -935,12 +935,13 @@ read_next_line (void) struct ui *ui = current_ui; char *prompt_ptr, control_prompt[256]; int i = 0; + int from_tty = ui->instream == ui->stdin_stream; if (control_level >= 254) error (_("Control nesting too deep!")); /* Set a prompt based on the nesting of the control commands. */ - if (ui->instream == stdin + if (from_tty || (ui->instream == 0 && deprecated_readline_hook != NULL)) { for (i = 0; i < control_level; i++) @@ -952,7 +953,7 @@ read_next_line (void) else prompt_ptr = NULL; - return command_line_input (prompt_ptr, ui->instream == stdin, "commands"); + return command_line_input (prompt_ptr, from_tty, "commands"); } /* Process one input line. If the command is an "end", return such an @@ -1256,7 +1257,7 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands, { struct command_line *head; - if (from_tty && input_from_terminal_p ()) + if (from_tty && input_interactive_p (current_ui)) { if (deprecated_readline_begin_hook) { @@ -1287,7 +1288,8 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands, do_cleanups (old_chain); } - if (deprecated_readline_end_hook && from_tty && input_from_terminal_p ()) + if (from_tty && input_interactive_p (current_ui) + && deprecated_readline_end_hook) { (*deprecated_readline_end_hook) (); } diff --git a/gdb/defs.h b/gdb/defs.h index 482ef1c..e8945ab 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -323,7 +323,9 @@ extern char *command_line_input (const char *, int, char *); extern void print_prompt (void); -extern int input_from_terminal_p (void); +struct ui; + +extern int input_interactive_p (struct ui *); extern int info_verbose; diff --git a/gdb/event-top.c b/gdb/event-top.c index 777823e..072ad2a 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -518,7 +518,7 @@ stdin_event_handler (int error, gdb_client_data client_data) { /* If stdin died, we may as well kill gdb. */ printf_unfiltered (_("error detected on stdin\n")); - quit_command ((char *) 0, stdin == ui->instream); + quit_command ((char *) 0, 0); } else { @@ -589,7 +589,7 @@ command_handler (char *command) struct cleanup *stat_chain; char *c; - if (ui->instream == stdin) + if (ui->instream == ui->stdin_stream) reinitialize_more_filter (); stat_chain = make_command_stats_cleanup (1); @@ -599,7 +599,7 @@ command_handler (char *command) ; if (c[0] != '#') { - execute_command (command, ui->instream == stdin); + execute_command (command, ui->instream == ui->stdin_stream); /* Do any commands attached to breakpoint we stopped at. */ bpstat_do_actions (); @@ -667,6 +667,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, char *rl, int repeat, char *annotation_suffix) { struct ui *ui = current_ui; + int from_tty = ui->instream == ui->stdin_stream; char *p1; char *cmd; @@ -681,7 +682,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 && ui->instream == stdin) + if (from_tty && annotation_level > 1) { printf_unfiltered (("\n\032\032post-")); puts_unfiltered (annotation_suffix); @@ -698,8 +699,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, } /* Do history expansion if that is wished. */ - if (history_expansion_p && ui->instream == stdin - && ISATTY (ui->instream)) + if (history_expansion_p && from_tty && input_interactive_p (current_ui)) { char *history_value; int expanded; @@ -743,7 +743,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. */ @@ -772,8 +772,7 @@ command_line_handler (char *rl) struct ui *ui = current_ui; char *cmd; - cmd = handle_line_of_input (line_buffer, rl, ui->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. @@ -781,7 +780,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 == ui->instream); + execute_command ("quit", 1); } else if (cmd == NULL) { @@ -838,7 +837,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 (ui->instream ? ui->instream : stdin); + c = fgetc (ui->instream != NULL ? ui->instream : ui->stdin_stream); if (c == EOF) { @@ -1086,7 +1085,7 @@ interruptible_select (int n, static void async_sigterm_handler (gdb_client_data arg) { - quit_force (NULL, stdin == current_ui->instream); + quit_force (NULL, 0); } /* See defs.h. */ diff --git a/gdb/inflow.c b/gdb/inflow.c index 4c80dbd..4cbcd5c 100644 --- a/gdb/inflow.c +++ b/gdb/inflow.c @@ -142,24 +142,6 @@ enum gdb_has_a_terminal_flag_enum } gdb_has_a_terminal_flag = have_not_checked; -/* The value of the "interactive-mode" setting. */ -static enum auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO; - -/* Implement the "show interactive-mode" option. */ - -static void -show_interactive_mode (struct ui_file *file, int from_tty, - struct cmd_list_element *c, - const char *value) -{ - if (interactive_mode == AUTO_BOOLEAN_AUTO) - fprintf_filtered (file, "Debugger's interactive mode " - "is %s (currently %s).\n", - value, gdb_has_a_terminal () ? "on" : "off"); - else - fprintf_filtered (file, "Debugger's interactive mode is %s.\n", value); -} - /* Set the initial tty state that is to be inherited by new inferiors. */ void @@ -172,9 +154,6 @@ set_initial_gdb_ttystate (void) int gdb_has_a_terminal (void) { - if (interactive_mode != AUTO_BOOLEAN_AUTO) - return interactive_mode == AUTO_BOOLEAN_TRUE; - switch (gdb_has_a_terminal_flag) { case yes: @@ -899,20 +878,6 @@ _initialize_inflow (void) add_info ("terminal", term_info, _("Print inferior's saved terminal status.")); - add_setshow_auto_boolean_cmd ("interactive-mode", class_support, - &interactive_mode, _("\ -Set whether GDB's standard input is a terminal."), _("\ -Show whether GDB's standard input is a terminal."), _("\ -If on, GDB assumes that standard input is a terminal. In practice, it\n\ -means that GDB should wait for the user to answer queries associated to\n\ -commands entered at the command prompt. If off, GDB assumes that standard\n\ -input is not a terminal, and uses the default answer to all queries.\n\ -If auto (the default), determine which mode to use based on the standard\n\ -input settings."), - NULL, - show_interactive_mode, - &setlist, &showlist); - terminal_is_ours = 1; /* OK, figure out whether we have job control. If neither termios nor diff --git a/gdb/main.c b/gdb/main.c index 8c9d563..6475ce6 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -334,7 +334,7 @@ captured_command_loop (void *data) error) we try to quit. If the quit is aborted, catch_errors() which called this catch the signal and restart the command loop. */ - quit_command (NULL, ui->instream == stdin); + quit_command (NULL, ui->instream == ui->stdin_stream); return 1; } diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index e9dfe8e..b18d034 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -285,7 +285,7 @@ mi_execute_command_wrapper (const char *cmd) { struct ui *ui = current_ui; - mi_execute_command (cmd, stdin == ui->instream); + mi_execute_command (cmd, ui->instream == ui->stdin_stream); } /* Observer for the synchronous_command_done notification. */ diff --git a/gdb/top.c b/gdb/top.c index 5883875..7506c45 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -259,12 +259,15 @@ new_ui (FILE *instream, FILE *outstream, FILE *errstream) ui = XCNEW (struct ui); ui->num = ++highest_ui_num; + ui->stdin_stream = instream; ui->instream = instream; ui->outstream = outstream; ui->errstream = errstream; ui->input_fd = fileno (ui->instream); + ui->input_interactive_p = ISATTY (ui->instream); + ui->m_gdb_stdin = stdio_fileopen (ui->instream); ui->m_gdb_stdout = stdio_fileopen (ui->outstream); ui->m_gdb_stderr = stderr_fileopen (ui->errstream); @@ -646,7 +649,7 @@ dont_repeat (void) /* If we aren't reading from standard input, we are saving the last thing read from stdin in line and don't want to delete it. Null lines won't repeat here in any case. */ - if (ui->instream == stdin) + if (ui->instream == ui->stdin_stream) *saved_command_line = 0; } @@ -1108,7 +1111,7 @@ gdb_safe_append_history (void) NULL is returned for end of file. - *If* the instream == stdin & stdin is a terminal, the line read is + *If* input is from an interactive stream (stdin), the line read is copied into the global 'saved_command_line' so that it can be repeated. @@ -1123,12 +1126,13 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) struct ui *ui = current_ui; const char *prompt = prompt_arg; char *cmd; + int from_tty = ui->instream == ui->stdin_stream; /* The annotation suffix must be non-NULL. */ if (annotation_suffix == NULL) annotation_suffix = ""; - if (annotation_level > 1 && ui->instream == stdin) + if (from_tty && annotation_level > 1) { char *local_prompt; @@ -1174,7 +1178,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) if (source_file_name != NULL) ++source_line_number; - if (annotation_level > 1 && ui->instream == stdin) + if (from_tty && annotation_level > 1) { puts_unfiltered ("\n\032\032pre-"); puts_unfiltered (annotation_suffix); @@ -1182,11 +1186,15 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) } /* Don't use fancy stuff if not talking to stdin. */ - if (deprecated_readline_hook && input_from_terminal_p ()) + if (deprecated_readline_hook + && from_tty + && input_interactive_p (current_ui)) { rl = (*deprecated_readline_hook) (prompt); } - else if (command_editing_p && input_from_terminal_p ()) + else if (command_editing_p + && from_tty + && input_interactive_p (current_ui)) { rl = gdb_readline_wrapper (prompt); } @@ -1561,9 +1569,25 @@ quit_force (char *args, int from_tty) /* Save the history information if it is appropriate to do so. */ TRY { - if (write_history_p && history_filename - && input_from_terminal_p ()) - gdb_safe_append_history (); + if (write_history_p && history_filename) + { + struct ui *ui; + int save = 0; + + /* History is currently shared between all UIs. If there's + any UI with a terminal, save history. */ + ALL_UIS (ui) + { + if (input_interactive_p (ui)) + { + save = 1; + break; + } + } + + if (save) + gdb_safe_append_history (); + } } CATCH (ex, RETURN_MASK_ALL) { @@ -1585,27 +1609,36 @@ quit_force (char *args, int from_tty) exit (exit_code); } -/* Returns whether GDB is running on a terminal and input is - currently coming from that terminal. */ +/* The value of the "interactive-mode" setting. */ +static enum auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO; -int -input_from_terminal_p (void) +/* Implement the "show interactive-mode" option. */ + +static void +show_interactive_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) { - struct ui *ui = current_ui; + if (interactive_mode == AUTO_BOOLEAN_AUTO) + fprintf_filtered (file, "Debugger's interactive mode " + "is %s (currently %s).\n", + value, gdb_has_a_terminal () ? "on" : "off"); + else + fprintf_filtered (file, "Debugger's interactive mode is %s.\n", value); +} + +/* Returns whether GDB is running on an interactive terminal. */ +int +input_interactive_p (struct ui *ui) +{ if (batch_flag) return 0; - if (gdb_has_a_terminal () && ui->instream == stdin) - return 1; - - /* If INSTREAM is unset, and we are not in a user command, we - must be in Insight. That's like having a terminal, for our - purposes. */ - if (ui->instream == NULL && !in_user_command) - return 1; + if (interactive_mode != AUTO_BOOLEAN_AUTO) + return interactive_mode == AUTO_BOOLEAN_TRUE; - return 0; + return ui->input_interactive_p; } static void @@ -2013,6 +2046,20 @@ When set, GDB uses the specified path to search for data files."), set_gdb_datadir, show_gdb_datadir, &setlist, &showlist); + + add_setshow_auto_boolean_cmd ("interactive-mode", class_support, + &interactive_mode, _("\ +Set whether GDB's standard input is a terminal."), _("\ +Show whether GDB's standard input is a terminal."), _("\ +If on, GDB assumes that standard input is a terminal. In practice, it\n\ +means that GDB should wait for the user to answer queries associated to\n\ +commands entered at the command prompt. If off, GDB assumes that standard\n\ +input is not a terminal, and uses the default answer to all queries.\n\ +If auto (the default), determine which mode to use based on the standard\n\ +input settings."), + NULL, + show_interactive_mode, + &setlist, &showlist); } void diff --git a/gdb/top.h b/gdb/top.h index a0fa391..cf94ee4 100644 --- a/gdb/top.h +++ b/gdb/top.h @@ -98,6 +98,9 @@ struct ui currently active. */ int secondary_prompt_depth; + /* The UI's stdin. Set to stdin for the main UI. */ + FILE *stdin_stream; + /* stdio stream that command input is being read from. Set to stdin normally. Set by source_command to the file we are sourcing. Set to NULL if we are executing a user-defined command or @@ -112,6 +115,11 @@ struct ui it with the event loop. */ int input_fd; + /* Whether ISATTY returns true on input_fd. Cached here because + quit_force needs to know this _after_ input_fd might be + closed. */ + int input_interactive_p; + /* See enum prompt_state's description. */ enum prompt_state prompt_state; diff --git a/gdb/utils.c b/gdb/utils.c index 78d2e98..c70e99c 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1052,7 +1052,7 @@ quit (void) if (sync_quit_force_run) { sync_quit_force_run = 0; - quit_force (NULL, stdin == ui->instream); + quit_force (NULL, 0); } #ifdef __MSDOS__ @@ -1271,7 +1271,8 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args) question we're asking, and then answer the default automatically. This way, important error messages don't get lost when talking to GDB over a pipe. */ - if (! input_from_terminal_p ()) + if (current_ui->instream != current_ui->stdin_stream + || !input_interactive_p (current_ui)) { target_terminal_ours_for_output (); wrap_here ("");