This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 03/23] Introduce "struct ui"
- From: Pedro Alves <palves at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 3 Feb 2016 16:43:38 +0000
- Subject: [PATCH 03/23] Introduce "struct ui"
- Authentication-results: sourceware.org; auth=none
- References: <1454517838-7784-1-git-send-email-palves at redhat dot com>
I'm aiming 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/event-top.c | 69 ++++++++++++++++++++++++------------------------------
gdb/event-top.h | 2 --
gdb/mi/mi-interp.c | 5 ++--
gdb/top.c | 10 ++++----
gdb/top.h | 33 +++++++++++++++++++++++++-
5 files changed, 71 insertions(+), 48 deletions(-)
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 969124e..736a77a 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -76,28 +76,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. */
@@ -179,6 +161,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
@@ -188,18 +172,18 @@ change_line_handler (void)
if (async_command_editing_p)
{
/* Turn on editing by using readline. */
- call_readline = rl_callback_read_char_wrapper;
- input_handler = command_line_handler;
+ ui->call_readline = rl_callback_read_char_wrapper;
+ ui->input_handler = command_line_handler;
}
else
{
/* Turn off editing by using gdb_readline2. */
gdb_rl_callback_handler_remove ();
- call_readline = gdb_readline_callback_no_editing;
+ ui->call_readline = gdb_readline_callback_no_editing;
/* 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;
}
}
@@ -232,12 +216,14 @@ gdb_rl_callback_handler_remove (void)
void
gdb_rl_callback_handler_install (const char *prompt)
{
+ struct ui *ui = current_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, ui->input_handler);
callback_handler_installed = 1;
}
@@ -370,15 +356,15 @@ top_level_prompt (void)
return xstrdup (prompt);
}
-/* Get a pointer to the command line builder. This is to used to
- construct a whole line of input from partial input. */
+static struct ui current_ui_;
+struct ui *current_ui = ¤t_ui_;
+
+/* Get a pointer to the current UI's line builder. */
static struct buffer *
get_line_builder (void)
{
- static struct buffer line_builder;
-
- return &line_builder;
+ return ¤t_ui->line_builder;
}
/* When there is an event ready on the stdin file descriptor, instead
@@ -389,6 +375,8 @@ get_line_builder (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"));
@@ -401,7 +389,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);
}
}
@@ -653,6 +641,7 @@ command_line_handler (char *rl)
void
gdb_readline_callback_no_editing (gdb_client_data client_data)
{
+ struct ui *ui = current_ui;
struct buffer *builder = get_line_builder ();
int c;
char *r;
@@ -685,7 +674,7 @@ gdb_readline_callback_no_editing (gdb_client_data client_data)
break;
}
xfree (buffer_finish (builder));
- (*input_handler) (NULL);
+ ui->input_handler (NULL);
return;
}
@@ -703,7 +692,7 @@ gdb_readline_callback_no_editing (gdb_client_data client_data)
buffer_grow_char (builder, '\0');
r = buffer_finish (builder);
- (*input_handler) (r);
+ ui->input_handler (r);
}
@@ -963,6 +952,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
@@ -985,19 +976,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 = rl_callback_read_char_wrapper;
+ ui->call_readline = rl_callback_read_char_wrapper;
}
else
{
async_command_editing_p = 0;
- call_readline = gdb_readline_callback_no_editing;
+ ui->call_readline = gdb_readline_callback_no_editing;
}
/* 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 44e2041..4f89626 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 80c8259..8542a16 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -174,6 +174,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... */
@@ -181,8 +182,8 @@ mi_interpreter_resume (void *data)
/* These overwrite some of the initialization done in
_intialize_event_loop. */
- call_readline = gdb_readline_callback_no_editing;
- input_handler = mi_execute_command_input_handler;
+ ui->call_readline = gdb_readline_callback_no_editing;
+ 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 8e5489e..21fbb0c 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -778,13 +778,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
@@ -810,13 +811,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 d5f1464..66dbd2c 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 line builder. This is to used to accumulate input until
+ we have a whole command line. */
+ struct buffer line_builder;
+
+ /* 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;
--
1.9.3