From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15437 invoked by alias); 2 Sep 2011 17:08:25 -0000 Received: (qmail 15419 invoked by uid 22791); 2 Sep 2011 17:08:23 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 02 Sep 2011 17:07:50 +0000 Received: (qmail 10020 invoked from network); 2 Sep 2011 17:07:49 -0000 Received: from unknown (HELO scottsdale.localnet) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 2 Sep 2011 17:07:49 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Flip the interpreter to synchronously wait for commands finishing, in command lists and similars Date: Fri, 02 Sep 2011 17:22:00 -0000 User-Agent: KMail/1.13.6 (Linux/2.6.38-11-generic; KDE/4.7.0; x86_64; ; ) MIME-Version: 1.0 Content-Type: Text/Plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Message-Id: <201109021807.41992.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-09/txt/msg00038.txt.bz2 Originally discussed in this thread: 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 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);