From a74e1786ac24d4ef1ce8a92a1ab06c727a462881 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 21 Jun 2016 01:11:44 +0100 Subject: [PATCH] Introduce "struct ui" This is a step towards supporting multiple consoles/MIs, each on its own stdio streams / terminal. See intro comment in top.h. (I've had trouble picking a name for this object. I've started out with "struct console" originally. But then this is about MI as well, and there's "interpreter-exec console", which is specifically about the CLI... So I changed to "struct terminal", but, then we have a terminal object that works when the input is not a terminal as well ... Then I sort of gave up and renamed it to "struct top_level". But it then gets horribly confusing when we talk about the "top level interpreter that's running on the current top level". In the end, I realized we're already sort of calling this "ui", in struct ui_out, struct ui_file, and a few coments here and there.) gdb/ChangeLog: 2016-06-21 Pedro Alves * event-top.c: Update readline-related comments. (input_handler, call_readline): Delete globals. (gdb_rl_callback_handler): Call the current UI's input_handler method. (change_line_handler): Adjust to set current UI's properties instead of globals. (current_ui_, current_ui): New globals. (get_command_line_buffer): Rewrite to refer to the current UI. (stdin_event_handler): Adjust to call the call_readline method of the current UI. (gdb_readline_no_editing_callback): Adjust to call the current UI's input_handler method. (gdb_setup_readline): Adjust to set current UI's properties instead of globals. * event-top.h (call_readline, input_handler): Delete declarations. * mi/mi-interp.c (mi_interpreter_resume): Adjust to set current UI's properties instead of globals. * top.c (gdb_readline_wrapper_cleanup): Adjust to set current UI's properties instead of globals. (gdb_readline_wrapper): Adjust to call and set current UI's methods instead of globals. * top.h: Include buffer.h and event-loop.h. (struct ui): New struct. (current_ui): New declaration. --- gdb/ChangeLog | 27 +++++++++++++++++ gdb/event-top.c | 74 ++++++++++++++++++---------------------------- gdb/event-top.h | 2 -- gdb/mi/mi-interp.c | 5 ++-- gdb/top.c | 10 ++++--- gdb/top.h | 33 ++++++++++++++++++++- 6 files changed, 97 insertions(+), 54 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 98f56ed317..9914281b7c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,30 @@ +2016-06-21 Pedro Alves + + * event-top.c: Update readline-related comments. + (input_handler, call_readline): Delete globals. + (gdb_rl_callback_handler): Call the current UI's input_handler + method. + (change_line_handler): Adjust to set current UI's properties + instead of globals. + (current_ui_, current_ui): New globals. + (get_command_line_buffer): Rewrite to refer to the current UI. + (stdin_event_handler): Adjust to call the call_readline method of + the current UI. + (gdb_readline_no_editing_callback): Adjust to call the current UI's + input_handler method. + (gdb_setup_readline): Adjust to set current UI's properties + instead of globals. + * event-top.h (call_readline, input_handler): Delete declarations. + * mi/mi-interp.c (mi_interpreter_resume): Adjust to set current + UI's properties instead of globals. + * top.c (gdb_readline_wrapper_cleanup): Adjust to set current UI's + properties instead of globals. + (gdb_readline_wrapper): Adjust to call and set current UI's + methods instead of globals. + * top.h: Include buffer.h and event-loop.h. + (struct ui): New struct. + (current_ui): New declaration. + 2016-06-21 Pedro Alves * ada-lang.c (ada_exception_name_addr_1): Add comment. diff --git a/gdb/event-top.c b/gdb/event-top.c index f43fd0a340..664543cfc6 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -75,28 +75,10 @@ static void async_stop_sig (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. */ @@ -217,10 +199,11 @@ static void gdb_rl_callback_handler (char *rl) { struct gdb_exception gdb_rl_expt = exception_none; + struct ui *ui = current_ui; TRY { - input_handler (rl); + ui->input_handler (rl); } CATCH (ex, RETURN_MASK_ALL) { @@ -261,6 +244,8 @@ cli_command_loop (void *data) static void change_line_handler (void) { + struct ui *ui = current_ui; + /* 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 @@ -270,18 +255,18 @@ change_line_handler (void) if (async_command_editing_p) { /* Turn on editing by using readline. */ - call_readline = gdb_rl_callback_read_char_wrapper; - input_handler = command_line_handler; + ui->call_readline = gdb_rl_callback_read_char_wrapper; + ui->input_handler = command_line_handler; } else { /* Turn off editing by using gdb_readline_no_editing_callback. */ gdb_rl_callback_handler_remove (); - call_readline = gdb_readline_no_editing_callback; + ui->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; + ui->input_handler = command_line_handler; } } @@ -452,22 +437,16 @@ top_level_prompt (void) return xstrdup (prompt); } -/* Get a pointer to the command line buffer. This is used to +static struct ui current_ui_; +struct ui *current_ui = ¤t_ui_; + +/* 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 @@ -478,6 +457,8 @@ get_command_line_buffer (void) void stdin_event_handler (int error, gdb_client_data client_data) { + struct ui *ui = current_ui; + if (error) { printf_unfiltered (_("error detected on stdin\n")); @@ -499,7 +480,7 @@ stdin_event_handler (int error, gdb_client_data client_data) do { call_stdin_event_handler_again_p = 0; - (*call_readline) (client_data); + ui->call_readline (client_data); } while (call_stdin_event_handler_again_p != 0); } } @@ -756,6 +737,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); @@ -795,7 +777,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; } @@ -812,7 +794,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); } @@ -1198,6 +1180,8 @@ set_async_editing_command (char *args, int from_tty, void gdb_setup_readline (void) { + 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 @@ -1220,19 +1204,19 @@ gdb_setup_readline (void) /* When a character is detected on instream by select or poll, readline will be invoked via this callback function. */ - call_readline = gdb_rl_callback_read_char_wrapper; + ui->call_readline = gdb_rl_callback_read_char_wrapper; } else { async_command_editing_p = 0; - call_readline = gdb_readline_no_editing_callback; + 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; - + ui->input_handler = command_line_handler; + /* Tell readline to use the same input stream that gdb uses. */ rl_instream = instream; diff --git a/gdb/event-top.h b/gdb/event-top.h index bef25309ff..04956a5579 100644 --- a/gdb/event-top.h +++ b/gdb/event-top.h @@ -57,8 +57,6 @@ extern void async_enable_stdin (void); extern int async_command_editing_p; extern int exec_done_display_p; extern struct prompts the_prompts; -extern void (*call_readline) (void *); -extern void (*input_handler) (char *); extern int input_fd; extern void (*after_char_processing_hook) (void); extern int call_stdin_event_handler_again_p; diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index 3bbdb1f989..4656e892b4 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -175,6 +175,7 @@ static int mi_interpreter_resume (void *data) { struct mi_interp *mi = (struct mi_interp *) data; + struct ui *ui = current_ui; /* As per hack note in mi_interpreter_init, swap in the output channels... */ @@ -182,8 +183,8 @@ mi_interpreter_resume (void *data) /* These overwrite some of the initialization done in _intialize_event_loop. */ - call_readline = gdb_readline_no_editing_callback; - input_handler = mi_execute_command_input_handler; + ui->call_readline = gdb_readline_no_editing_callback; + ui->input_handler = mi_execute_command_input_handler; async_command_editing_p = 0; /* FIXME: This is a total hack for now. PB's use of the MI implicitly relies on a bug in the async support which allows diff --git a/gdb/top.c b/gdb/top.c index f5ef7186fd..cae90d6597 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -794,13 +794,14 @@ struct gdb_readline_wrapper_cleanup static void gdb_readline_wrapper_cleanup (void *arg) { + struct ui *ui = current_ui; struct gdb_readline_wrapper_cleanup *cleanup = (struct gdb_readline_wrapper_cleanup *) arg; rl_already_prompted = cleanup->already_prompted_orig; - gdb_assert (input_handler == gdb_readline_wrapper_line); - input_handler = cleanup->handler_orig; + gdb_assert (ui->input_handler == gdb_readline_wrapper_line); + ui->input_handler = cleanup->handler_orig; /* Don't restore our input handler in readline yet. That would make readline prep the terminal (putting it in raw mode), while the @@ -826,13 +827,14 @@ gdb_readline_wrapper_cleanup (void *arg) char * gdb_readline_wrapper (const char *prompt) { + struct ui *ui = current_ui; struct cleanup *back_to; struct gdb_readline_wrapper_cleanup *cleanup; char *retval; cleanup = XNEW (struct gdb_readline_wrapper_cleanup); - cleanup->handler_orig = input_handler; - input_handler = gdb_readline_wrapper_line; + cleanup->handler_orig = ui->input_handler; + ui->input_handler = gdb_readline_wrapper_line; cleanup->already_prompted_orig = rl_already_prompted; diff --git a/gdb/top.h b/gdb/top.h index a498f390eb..fc4e90a8a1 100644 --- a/gdb/top.h +++ b/gdb/top.h @@ -20,7 +20,38 @@ #ifndef TOP_H #define TOP_H -struct buffer; +#include "buffer.h" +#include "event-loop.h" + +/* All about a user interface instance. Each user interface has its + own I/O files/streams, readline state, its own top level + interpreter (for the main UI, this is the interpreter specified + with -i on the command line) and secondary interpreters (for + interpreter-exec ...), etc. There's always one UI associated with + stdin/stdout/stderr, but the user can create secondary UIs, for + example, to create a separate MI channel on its own stdio + streams. */ + +struct ui +{ + /* The UI's command line buffer. This is to used to accumulate + input until we have a whole command line. */ + struct buffer line_buffer; + + /* The callback used by the event loop whenever an event is detected + on the UI's input file descriptor. This function incrementally + builds a buffer 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 the INPUT_HANDLER callback + (see below). */ + void (*call_readline) (gdb_client_data); + + /* The function to invoke when a complete line of input is ready for + processing. */ + void (*input_handler) (char *); +}; + +extern struct ui *current_ui; /* From top.c. */ extern char *saved_command_line;