* Flip the interpreter to synchronously wait for commands finishing, in command lists and similars
@ 2011-09-02 17:22 Pedro Alves
2011-09-03 9:21 ` Matt Rice
0 siblings, 1 reply; 3+ messages in thread
From: Pedro Alves @ 2011-09-02 17:22 UTC (permalink / raw)
To: gdb-patches
Originally discussed in this thread:
<http://sourceware.org/ml/gdb/2011-08/msg00068.html>
It flips the _interpreter_ (not the target, like we used to
with the old target_async_mask for infcalls) to synchronous
mode -- the target still runs asynchronously, but the
interpreter synchronously waits for command completion (as
well as listening for other event sources) before returning.
It fixes the define.exp:nextwhere FAIL in async mode, where
we have
(gdb) define nw
next
where
end
(gdb) nw
and we'd run "where" before the target had finished and
stopped for the "next".
With this patch, synchronous execution commands (the regular step, next,
etc., that is, those with an & suffixed) with a target running
in async mode work correctly (AFAICT) with all current use cases. We
can consider flipping on async on by default, and then incrementally
convert specific paths to state machines, for new use cases, rather than
delaying flipping on async on by default until _everything_ is converted
into a state-machine.
Tested on x86_64-linux (w/ and wo/ target-async forced on) and applied.
--
Pedro Alves
2011-09-02 Pedro Alves <pedro@codesourcery.com>
gdb/
* top.c: Include interps.h.
(execute_command): If the target can async, but the interpreter is
in sync mode, synchronously wait for the command to finish before
returning.
(execute_command_to_string): Force the interpreter to sync mode.
* infrun.c: Include interps.h.
(fetch_inferior_event): Don't restore the prompt yet if the
interpreter is in sync mode.
* interps.c (interpreter_async): New global.
* interps.h (interpreter_async): Declare.
* inf-loop.c: Include interps.h.
(inferior_event_handler): Don't print the language change or run
breakpoint commands yet if the interpreter in is sync mode.
* main.c (captured_command_loop): Flip the interpreter to async
mode.
* cli/cli-script.c: Include interps.h.
(execute_user_command, while_command, if_command): Force the
interpreter to sync mode.
* python/python.c: Include interps.h.
(python_command, execute_gdb_command): Force the interpreter to
sync mode.
---
gdb/cli/cli-script.c | 16 ++++++++++++++++
gdb/inf-loop.c | 31 +++++++++++++++++++------------
gdb/infrun.c | 3 ++-
gdb/interps.c | 6 ++++++
gdb/interps.h | 9 +++++++++
gdb/main.c | 4 ++++
gdb/python/python.c | 8 ++++++++
gdb/top.c | 17 ++++++++++++++++-
8 files changed, 80 insertions(+), 14 deletions(-)
Index: src/gdb/top.c
===================================================================
--- src.orig/gdb/top.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/top.c 2011-08-31 15:34:29.010142005 +0100
@@ -48,6 +48,7 @@
#include "event-loop.h"
#include "gdbthread.h"
#include "python/python.h"
+#include "interps.h"
/* readline include files. */
#include "readline/readline.h"
@@ -441,7 +442,18 @@ execute_command (char *p, int from_tty)
deprecated_call_command_hook (c, arg, from_tty & caution);
else
cmd_func (c, arg, from_tty & caution);
-
+
+ /* If the interpreter is in sync mode (we're running a user
+ command's list, running command hooks or similars), and we
+ just ran a synchronous command that started the target, wait
+ for that command to end. */
+ if (!interpreter_async && sync_execution && is_running (inferior_ptid))
+ {
+ while (gdb_do_one_event () >= 0)
+ if (!sync_execution)
+ break;
+ }
+
/* If this command has been post-hooked, run the hook last. */
execute_cmd_post_hook (c);
@@ -497,6 +509,9 @@ execute_command_to_string (char *p, int
restoration callbacks. */
cleanup = set_batch_flag_and_make_cleanup_restore_page_info ();
+ make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
str_file = mem_fileopen ();
make_cleanup_ui_file_delete (str_file);
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/infrun.c 2011-08-31 15:34:29.010142005 +0100
@@ -55,6 +55,7 @@
#include "jit.h"
#include "tracepoint.h"
#include "continuations.h"
+#include "interps.h"
/* Prototypes for local functions */
@@ -2814,7 +2815,7 @@ fetch_inferior_event (void *client_data)
/* If the inferior was in sync execution mode, and now isn't,
restore the prompt. */
- if (was_sync && !sync_execution)
+ if (interpreter_async && was_sync && !sync_execution)
display_gdb_prompt (0);
}
Index: src/gdb/interps.c
===================================================================
--- src.orig/gdb/interps.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/interps.c 2011-08-31 15:34:29.010142005 +0100
@@ -43,6 +43,12 @@
#include "exceptions.h"
#include "continuations.h"
+/* True if the current interpreter in is async mode. See interps.h
+ for more details. This starts out disabled, until all the explicit
+ command line arguments (e.g., `gdb -ex "start" -ex "next"') are
+ processed. */
+int interpreter_async = 0;
+
struct interp
{
/* This is the name in "-i=" and set interpreter. */
Index: src/gdb/interps.h
===================================================================
--- src.orig/gdb/interps.h 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/interps.h 2011-08-31 15:34:29.010142005 +0100
@@ -69,6 +69,15 @@ extern void current_interp_command_loop
extern void *top_level_interpreter_data (void);
extern struct interp *top_level_interpreter (void);
+/* True if the current interpreter is in async mode, false if in sync
+ mode. If in sync mode, running a synchronous execution command
+ (with execute_command, e.g, "next") will not return until the
+ command is finished. If in async mode, then running a synchronous
+ command returns right after resuming the target. Waiting for the
+ command's completion is later done on the top event loop (using
+ continuations). */
+extern int interpreter_async;
+
extern void clear_interpreter_hooks (void);
/* well-known interpreters */
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/inf-loop.c 2011-08-31 15:34:54.350142010 +0100
@@ -29,6 +29,7 @@
#include "language.h"
#include "gdbthread.h"
#include "continuations.h"
+#include "interps.h"
static int fetch_inferior_event_wrapper (gdb_client_data client_data);
@@ -40,7 +41,6 @@ void
inferior_event_handler (enum inferior_event_type event_type,
gdb_client_data client_data)
{
- struct gdb_exception e;
int was_sync = 0;
struct cleanup *cleanup_if_error = make_bpstat_clear_actions_cleanup ();
@@ -109,19 +109,26 @@ inferior_event_handler (enum inferior_ev
else
do_all_continuations (0);
- if (info_verbose
- && current_language != expected_language
- && language_mode == language_mode_auto)
- language_info (1); /* Print what changed. */
-
- /* Don't propagate breakpoint commands errors. Either we're
- stopping or some command resumes the inferior. The user will
- be informed. */
- TRY_CATCH (e, RETURN_MASK_ALL)
+ /* When running a command list (from a user command, say), these
+ are only run when the command list is all done. */
+ if (interpreter_async)
{
- bpstat_do_actions ();
+ volatile struct gdb_exception e;
+
+ if (info_verbose
+ && current_language != expected_language
+ && language_mode == language_mode_auto)
+ language_info (1); /* Print what changed. */
+
+ /* Don't propagate breakpoint commands errors. Either we're
+ stopping or some command resumes the inferior. The user will
+ be informed. */
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ bpstat_do_actions ();
+ }
+ exception_print (gdb_stderr, e);
}
- exception_print (gdb_stderr, e);
if (!was_sync
&& exec_done_display_p
Index: src/gdb/main.c
===================================================================
--- src.orig/gdb/main.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/main.c 2011-08-31 15:34:29.010142005 +0100
@@ -227,6 +227,10 @@ get_init_files (char **system_gdbinit,
static int
captured_command_loop (void *data)
{
+ /* Top-level execution commands can be run on the background from
+ here on. */
+ interpreter_async = 1;
+
current_interp_command_loop ();
/* FIXME: cagney/1999-11-05: A correct command_loop() implementaton
would clean things up (restoring the cleanup chain) to the state
Index: src/gdb/cli/cli-script.c
===================================================================
--- src.orig/gdb/cli/cli-script.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/cli/cli-script.c 2011-08-31 15:34:29.010142005 +0100
@@ -35,6 +35,7 @@
#include "gdb_assert.h"
#include "python/python.h"
+#include "interps.h"
/* Prototypes for local functions. */
@@ -338,6 +339,9 @@ execute_user_command (struct cmd_list_el
not confused with Insight. */
in_user_command = 1;
+ make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
command_nest_depth++;
while (cmdlines)
{
@@ -598,6 +602,7 @@ void
while_command (char *arg, int from_tty)
{
struct command_line *command = NULL;
+ struct cleanup *old_chain;
control_level = 1;
command = get_command_line (while_control, arg);
@@ -605,8 +610,13 @@ while_command (char *arg, int from_tty)
if (command == NULL)
return;
+ old_chain = make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
execute_control_command_untraced (command);
free_command_lines (&command);
+
+ do_cleanups (old_chain);
}
/* "if" command support. Execute either the true or false arm depending
@@ -616,6 +626,7 @@ void
if_command (char *arg, int from_tty)
{
struct command_line *command = NULL;
+ struct cleanup *old_chain;
control_level = 1;
command = get_command_line (if_control, arg);
@@ -623,8 +634,13 @@ if_command (char *arg, int from_tty)
if (command == NULL)
return;
+ old_chain = make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
execute_control_command_untraced (command);
free_command_lines (&command);
+
+ do_cleanups (old_chain);
}
/* Cleanup */
Index: src/gdb/python/python.c
===================================================================
--- src.orig/gdb/python/python.c 2011-08-31 15:34:27.000000000 +0100
+++ src/gdb/python/python.c 2011-08-31 15:34:29.020142005 +0100
@@ -52,6 +52,7 @@ static int gdbpy_should_print_stack = 0;
#include "target.h"
#include "gdbthread.h"
#include "observer.h"
+#include "interps.h"
static PyMethodDef GdbMethods[];
@@ -199,6 +200,10 @@ python_command (char *arg, int from_tty)
struct cleanup *cleanup;
cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
while (arg && *arg && isspace (*arg))
++arg;
if (arg && *arg)
@@ -378,6 +383,9 @@ execute_gdb_command (PyObject *self, PyO
char *copy = xstrdup (arg);
struct cleanup *cleanup = make_cleanup (xfree, copy);
+ make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
prevent_dont_repeat ();
if (to_string)
result = execute_command_to_string (copy, from_tty);
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: Flip the interpreter to synchronously wait for commands finishing, in command lists and similars
2011-09-02 17:22 Flip the interpreter to synchronously wait for commands finishing, in command lists and similars Pedro Alves
@ 2011-09-03 9:21 ` Matt Rice
2011-09-05 14:48 ` Pedro Alves
0 siblings, 1 reply; 3+ messages in thread
From: Matt Rice @ 2011-09-03 9:21 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Fri, Sep 2, 2011 at 10:07 AM, Pedro Alves <pedro@codesourcery.com> wrote:
>
> With this patch, synchronous execution commands (the regular step, next,
> etc., that is, those with an & suffixed) with a target running
> in async mode work correctly (AFAICT) with all current use cases. We
> can consider flipping on async on by default, and then incrementally
> convert specific paths to state machines, for new use cases, rather than
> delaying flipping on async on by default until _everything_ is converted
> into a state-machine.
I was hoping this might fix, (but doesn't seem to) the following case:
./gdb/gdb -ex 'set target-async on' -ex 'attach 7625' -ex 'continue'
./gdb/gdb -ex 'set target-async on' -ex 'attach 7625' -ex 'continue&'
both these commands exhibit:
Continuing.
Program received signal SIGSTOP, Stopped (signal).
.....
(gdb)
thus changing the behavior of '-ex continue' should we turn
target-async on by default.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Flip the interpreter to synchronously wait for commands finishing, in command lists and similars
2011-09-03 9:21 ` Matt Rice
@ 2011-09-05 14:48 ` Pedro Alves
0 siblings, 0 replies; 3+ messages in thread
From: Pedro Alves @ 2011-09-05 14:48 UTC (permalink / raw)
To: Matt Rice; +Cc: gdb-patches
On Saturday 03 September 2011 00:28:15, Matt Rice wrote:
> On Fri, Sep 2, 2011 at 10:07 AM, Pedro Alves <pedro@codesourcery.com> wrote:
> >
> > With this patch, synchronous execution commands (the regular step, next,
> > etc., that is, those with an & suffixed) with a target running
> > in async mode work correctly (AFAICT) with all current use cases. We
> > can consider flipping on async on by default, and then incrementally
> > convert specific paths to state machines, for new use cases, rather than
> > delaying flipping on async on by default until _everything_ is converted
> > into a state-machine.
>
> I was hoping this might fix, (but doesn't seem to) the following case:
>
> ./gdb/gdb -ex 'set target-async on' -ex 'attach 7625' -ex 'continue'
> ./gdb/gdb -ex 'set target-async on' -ex 'attach 7625' -ex 'continue&'
>
> both these commands exhibit:
> Continuing.
>
> Program received signal SIGSTOP, Stopped (signal).
> .....
> (gdb)
Thanks. An attach ends with a TARGET_SIGNAL_STOP/SIGSTOP, that is
normally suppressed by STOP_QUIETLY_NO_SIGSTOP, but we weren't entering
the new loop in execute_command because the current thread isn't marked
running at that point yet. So, "continue" ran before the attach was
complete, and "continue"ing calls clear_proceed_status
which wipes inferior->stop_soon. By the time we process the TARGET_SIGNAL_STOP,
we can no longer explain it, and so report it as a regular SIGSTOP.
I had added the "is_running()" check for the hook-stop-continue.exp test,
as otherwise, when we went to go execute the first command in the hook-stop
command list, being that a command that doesn't start the target
running, we'd enter the loop in execute_command:
if (!interpreter_async && sync_execution)
{
while (gdb_do_one_event () >= 0)
if (!sync_execution)
break;
}
but we'd never leave it, hanging in gdb_do_one_event, because the
previous command had already finished, and the target was stopped
already, but sync_execution was still set.
Here's a better fix for that issue, which fixes your example
too. Clear sync_execution before running the hook-stop, as
soon as the previous sync execution command finishes.
This make a hell lot more sense. I don't know why I didn't
think of it before :-).
Tested it on x86_64-linux (async) and applied.
> thus changing the behavior of '-ex continue' should we turn
> target-async on by default.
ECANTPARSE?
--
Pedro Alves
2011-09-05 Pedro Alves <pedro@codesourcery.com>
gdb/
* inf-loop.c (execute_command): Don't check if the current thread
if running before synchronously waiting for command completion.
* infrun.c (fetch_inferior_event): Handle "set exec-done-display"
here.
(normal_stop): Call async_enable_stdin here.
* inf-loop.c (inferior_event_handler): Don't call
async_enable_stdin, nor handle "set exec-done-display" here.
---
gdb/inf-loop.c | 14 --------------
gdb/infrun.c | 17 +++++++++++++++--
gdb/top.c | 2 +-
3 files changed, 16 insertions(+), 17 deletions(-)
Index: src/gdb/top.c
===================================================================
--- src.orig/gdb/top.c 2011-09-05 15:11:13.063963929 +0100
+++ src/gdb/top.c 2011-09-05 15:11:54.333963936 +0100
@@ -447,7 +447,7 @@ execute_command (char *p, int from_tty)
command's list, running command hooks or similars), and we
just ran a synchronous command that started the target, wait
for that command to end. */
- if (!interpreter_async && sync_execution && is_running (inferior_ptid))
+ if (!interpreter_async && sync_execution)
{
while (gdb_do_one_event () >= 0)
if (!sync_execution)
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2011-09-05 15:11:12.353963929 +0100
+++ src/gdb/infrun.c 2011-09-05 15:11:54.333963936 +0100
@@ -2713,6 +2713,7 @@ fetch_inferior_event (void *client_data)
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
struct cleanup *ts_old_chain;
int was_sync = sync_execution;
+ int cmd_done = 0;
memset (ecs, 0, sizeof (*ecs));
@@ -2804,7 +2805,10 @@ fetch_inferior_event (void *client_data)
&& ecs->event_thread->control.stop_step)
inferior_event_handler (INF_EXEC_CONTINUE, NULL);
else
- inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ {
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ cmd_done = 1;
+ }
}
/* No error, don't finish the thread states yet. */
@@ -2814,9 +2818,17 @@ fetch_inferior_event (void *client_data)
do_cleanups (old_chain);
/* If the inferior was in sync execution mode, and now isn't,
- restore the prompt. */
+ restore the prompt (a synchronous execution command has finished,
+ and we're ready for input). */
if (interpreter_async && was_sync && !sync_execution)
display_gdb_prompt (0);
+
+ if (cmd_done
+ && !was_sync
+ && exec_done_display_p
+ && (ptid_equal (inferior_ptid, null_ptid)
+ || !is_running (inferior_ptid)))
+ printf_unfiltered (_("completed.\n"));
}
/* Record the frame and location we're currently stepping through. */
@@ -5814,6 +5826,7 @@ normal_stop (void)
goto done;
target_terminal_ours ();
+ async_enable_stdin ();
/* Set the current source location. This will also happen if we
display the frame below, but the current SAL will be incorrect
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c 2011-09-05 15:11:12.353963929 +0100
+++ src/gdb/inf-loop.c 2011-09-05 15:11:54.333963936 +0100
@@ -41,7 +41,6 @@ void
inferior_event_handler (enum inferior_event_type event_type,
gdb_client_data client_data)
{
- int was_sync = 0;
struct cleanup *cleanup_if_error = make_bpstat_clear_actions_cleanup ();
switch (event_type)
@@ -63,7 +62,6 @@ inferior_event_handler (enum inferior_ev
break;
case INF_EXEC_COMPLETE:
-
if (!non_stop)
{
/* Unregister the inferior from the event loop. This is done
@@ -73,12 +71,6 @@ inferior_event_handler (enum inferior_ev
target_async (NULL, 0);
}
- /* The call to async_enable_stdin below resets 'sync_execution'.
- However, if sync_execution is 1 now, we also need to show the
- prompt below, so save the current value. */
- was_sync = sync_execution;
- async_enable_stdin ();
-
/* Do all continuations associated with the whole inferior (not
a particular thread). */
if (!ptid_equal (inferior_ptid, null_ptid))
@@ -129,12 +121,6 @@ inferior_event_handler (enum inferior_ev
}
exception_print (gdb_stderr, e);
}
-
- if (!was_sync
- && exec_done_display_p
- && (ptid_equal (inferior_ptid, null_ptid)
- || !is_running (inferior_ptid)))
- printf_unfiltered (_("completed.\n"));
break;
case INF_EXEC_CONTINUE:
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-09-05 14:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-02 17:22 Flip the interpreter to synchronously wait for commands finishing, in command lists and similars Pedro Alves
2011-09-03 9:21 ` Matt Rice
2011-09-05 14:48 ` Pedro Alves
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox