Async mode fixes.

* Makefile.in (infcmd.o, inf-loop.o): Update dependencies.
        * breakpoint.c (bpstat_do_actions): In async mode,
        don't jump to top expecting stop_bpstat to be already
        updated.
        * event-loop.c (start_event_loop): Call async_enable_stdin
        on exception.
        * event-top.c (async_enable_stdin): Do nothing if sync_execution
        is not set.
        (command_handler): Do not setup continuation here.
        (command_line_handler_continuation): Move to...
        * top.c (command_line_handler_continuation): ... here.
        (execute_command): In async mode, register continuation.
        Don't check frame's language in running in async mode.
        * exceptions.c (throw_exception): Don't do exec_error_cleanups.
        * inf-loop.c (complete_execution): Inline into...
        (inferior_event_handler): ... here.  Clear target_executing before
        doing any cleanups.  Don't try to show prompt if the target was
        resumed.
        * infcmd.c (signal_command): Add support for async mode.
        (finish_command): Only add continuation if the target was
        successfully resumed.
        * remote.c (init_async_opts): Register to_get_thread_local_address
        handler.
        * mi/mi-interp.c (mi_cmd_interpreter_exec): Don't mess
        with sync_execution.
        * tui/tui-interp.c (tui_command_loop): Call async_enable_stdin
        on exception.
This commit is contained in:
Vladimir Prus 2008-03-14 18:57:44 +00:00
parent c04ea773f9
commit 32c1e744c1
12 changed files with 237 additions and 127 deletions

View file

@ -1,3 +1,34 @@
2008-03-14 Vladimir Prus <vladimir@codesourcery.com>
Async mode fixes.
* Makefile.in (infcmd.o, inf-loop.o): Update dependencies.
* breakpoint.c (bpstat_do_actions): In async mode,
don't jump to top expecting stop_bpstat to be already
updated.
* event-loop.c (start_event_loop): Call async_enable_stdin
on exception.
* event-top.c (async_enable_stdin): Do nothing if sync_execution
is not set.
(command_handler): Do not setup continuation here.
(command_line_handler_continuation): Move to...
* top.c (command_line_handler_continuation): ... here.
(execute_command): In async mode, register continuation.
Don't check frame's language in running in async mode.
* exceptions.c (throw_exception): Don't do exec_error_cleanups.
* inf-loop.c (complete_execution): Inline into...
(inferior_event_handler): ... here. Clear target_executing before
doing any cleanups. Don't try to show prompt if the target was
resumed.
* infcmd.c (signal_command): Add support for async mode.
(finish_command): Only add continuation if the target was
successfully resumed.
* remote.c (init_async_opts): Register to_get_thread_local_address
handler.
* mi/mi-interp.c (mi_cmd_interpreter_exec): Don't mess
with sync_execution.
* tui/tui-interp.c (tui_command_loop): Call async_enable_stdin
on exception.
2008-03-14 Daniel Jacobowitz <dan@codesourcery.com>
* corefile.c (reopen_exec_file): Use exec_bfd_mtime.

View file

@ -2291,9 +2291,10 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
$(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \
$(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \
$(solib_h) $(gdb_assert_h) $(observer_h) $(target_descriptions_h) \
$(user_regs_h)
$(user_regs_h) $(exceptions_h)
inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \
$(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h)
$(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) \
$(language_h)
inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
$(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \
$(inflow_h) $(gdb_select_h)

View file

@ -2114,11 +2114,30 @@ top:
do_cleanups (this_cmd_tree_chain);
if (breakpoint_proceeded)
/* The inferior is proceeded by the command; bomb out now.
The bpstat chain has been blown away by wait_for_inferior.
But since execution has stopped again, there is a new bpstat
to look at, so start over. */
goto top;
{
if (target_can_async_p ())
/* If we are in async mode, then the target might
be still running, not stopped at any breakpoint,
so nothing for us to do here -- just return to
the event loop. */
break;
else
/* In sync mode, when execute_control_command returns
we're already standing on the next breakpoint.
Breakpoint commands for that stop were not run,
since execute_command does not run breakpoint
commands -- only command_line_handler does, but
that one is not involved in execution of breakpoint
commands. So, we can now execute breakpoint commands.
There's an implicit assumption that we're called with
stop_bpstat, so our parameter is the new bpstat to
handle.
It should be noted that making execute_command do
bpstat actions is not an option -- in this case we'll
have recursive invocation of bpstat for each breakpoint
with a command, and can easily blow up GDB stack. */
goto top;
}
}
do_cleanups (old_chain);
}

View file

@ -411,6 +411,10 @@ start_event_loop (void)
if (gdb_result == 0)
{
/* If any exception escaped to here, we better enable
stdin. Otherwise, any command that calls async_disable_stdin,
and then throws, will leave stdin inoperable. */
async_enable_stdin ((void *) 0);
/* FIXME: this should really be a call to a hook that is
interface specific, because interfaces can display the
prompt in their own way. */

View file

@ -44,7 +44,6 @@
static void rl_callback_read_char_wrapper (gdb_client_data client_data);
static void command_line_handler (char *rl);
static void command_line_handler_continuation (struct continuation_arg *arg);
static void change_line_handler (void);
static void change_annotation_level (void);
static void command_handler (char *command);
@ -438,13 +437,16 @@ stdin_event_handler (int error, gdb_client_data client_data)
void
async_enable_stdin (void *dummy)
{
/* See NOTE in async_disable_stdin() */
/* FIXME: cagney/1999-09-27: Call this before clearing
sync_execution. Current target_terminal_ours() implementations
check for sync_execution before switching the terminal. */
target_terminal_ours ();
pop_prompt ();
sync_execution = 0;
if (sync_execution)
{
/* See NOTE in async_disable_stdin() */
/* FIXME: cagney/1999-09-27: Call this before clearing
sync_execution. Current target_terminal_ours() implementations
check for sync_execution before switching the terminal. */
target_terminal_ours ();
pop_prompt ();
sync_execution = 0;
}
}
/* Disable reads from stdin (the console) marking the command as
@ -480,8 +482,6 @@ command_handler (char *command)
{
struct cleanup *old_chain;
int stdin_is_tty = ISATTY (stdin);
struct continuation_arg *arg1;
struct continuation_arg *arg2;
long time_at_cmd_start;
#ifdef HAVE_SBRK
long space_at_cmd_start = 0;
@ -517,24 +517,6 @@ command_handler (char *command)
execute_command (command, instream == stdin);
/* Set things up for this function to be compete later, once the
execution has completed, if we are doing an execution command,
otherwise, just go ahead and finish. */
if (target_can_async_p () && target_executing)
{
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg2 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = arg2;
arg2->next = NULL;
arg1->data.longint = time_at_cmd_start;
#ifdef HAVE_SBRK
arg2->data.longint = space_at_cmd_start;
#endif
add_continuation (command_line_handler_continuation, arg1);
}
/* Do any commands attached to breakpoint we stopped at. Only if we
are always running synchronously. Or if we have just executed a
command that doesn't start the target. */
@ -567,43 +549,6 @@ command_handler (char *command)
}
}
/* Do any commands attached to breakpoint we stopped at. Only if we
are always running synchronously. Or if we have just executed a
command that doesn't start the target. */
void
command_line_handler_continuation (struct continuation_arg *arg)
{
extern int display_time;
extern int display_space;
long time_at_cmd_start = arg->data.longint;
long space_at_cmd_start = arg->next->data.longint;
bpstat_do_actions (&stop_bpstat);
/*do_cleanups (old_chain); *//*?????FIXME????? */
if (display_time)
{
long cmd_time = get_run_time () - time_at_cmd_start;
printf_unfiltered (_("Command execution time: %ld.%06ld\n"),
cmd_time / 1000000, cmd_time % 1000000);
}
if (display_space)
{
#ifdef HAVE_SBRK
char *lim = (char *) sbrk (0);
long space_now = lim - lim_at_start;
long space_diff = space_now - space_at_cmd_start;
printf_unfiltered (_("Space used: %ld (%c%ld for this command)\n"),
space_now,
(space_diff >= 0 ? '+' : '-'),
space_diff);
#endif
}
}
/* Handle a complete line of input. This is called by the callback
mechanism within the readline library. Deal with incomplete commands
as well, by saving the partial input in a global buffer. */

View file

@ -221,10 +221,12 @@ throw_exception (struct gdb_exception exception)
disable_current_display ();
do_cleanups (ALL_CLEANUPS);
/* When we implement non-stop mode, this should be redone. If we get
exception in a command pertaining to one thread, or maybe even not
involving inferior at all, we should not do exec cleanups for all
threads. */
if (target_can_async_p () && !target_executing)
do_exec_cleanups (ALL_CLEANUPS);
if (sync_execution)
do_exec_error_cleanups (ALL_CLEANUPS);
/* Jump to the containing catch_errors() call, communicating REASON
to that call via setjmp's return value. Note that REASON can't

View file

@ -25,9 +25,9 @@
#include "inf-loop.h"
#include "remote.h"
#include "exceptions.h"
#include "language.h"
static int fetch_inferior_event_wrapper (gdb_client_data client_data);
static void complete_execution (void);
void
inferior_event_handler_wrapper (gdb_client_data client_data)
@ -43,6 +43,7 @@ void
inferior_event_handler (enum inferior_event_type event_type,
gdb_client_data client_data)
{
int was_sync = 0;
switch (event_type)
{
case INF_ERROR:
@ -70,11 +71,52 @@ inferior_event_handler (enum inferior_event_type event_type,
break;
case INF_EXEC_COMPLETE:
/* Is there anything left to do for the command issued to
complete? */
/* This is the first thing to do -- so that continuations know that
the target is stopped. For example, command_line_handler_continuation
will run breakpoint commands, and if we think that the target is
running, we'll refuse to execute most commands. MI continuation
presently uses target_executing to either print or not print *stopped. */
target_executing = 0;
/* Unregister the inferior from the event loop. This is done so that
when the inferior is not running we don't get distracted by
spurious inferior output. */
if (target_has_execution)
target_async (NULL, 0);
/* Calls to do_exec_error_cleanup below will call async_enable_stdin,
and that resets 'sync_execution'. However, if we were running
in sync execution mode, we also need to display the prompt. */
was_sync = sync_execution;
if (was_sync)
do_exec_error_cleanups (ALL_CLEANUPS);
do_all_continuations ();
/* Reset things after target has stopped for the async commands. */
complete_execution ();
if (current_language != expected_language)
{
if (language_mode == language_mode_auto)
{
language_info (1); /* Print what changed. */
}
}
/* If the continuation did not start the target again,
prepare for interation with the user. */
if (!target_executing)
{
if (was_sync)
{
display_gdb_prompt (0);
}
else
{
if (exec_done_display_p)
printf_unfiltered (_("completed.\n"));
}
}
break;
case INF_EXEC_CONTINUE:
@ -103,29 +145,3 @@ fetch_inferior_event_wrapper (gdb_client_data client_data)
fetch_inferior_event (client_data);
return 1;
}
/* Reset proper settings after an asynchronous command has finished.
If the execution command was in synchronous mode, register stdin
with the event loop, and reset the prompt. */
static void
complete_execution (void)
{
target_executing = 0;
/* Unregister the inferior from the event loop. This is done so that
when the inferior is not running we don't get distracted by
spurious inferior output. */
target_async (NULL, 0);
if (sync_execution)
{
do_exec_error_cleanups (ALL_CLEANUPS);
display_gdb_prompt (0);
}
else
{
if (exec_done_display_p)
printf_unfiltered (_("completed.\n"));
}
}

View file

@ -48,6 +48,7 @@
#include "observer.h"
#include "target-descriptions.h"
#include "user-regs.h"
#include "exceptions.h"
/* Functions exported for general use, in inferior.h: */
@ -1005,10 +1006,28 @@ static void
signal_command (char *signum_exp, int from_tty)
{
enum target_signal oursig;
int async_exec = 0;
dont_repeat (); /* Too dangerous. */
ERROR_NO_INFERIOR;
/* Find out whether we must run in the background. */
if (signum_exp != NULL)
async_exec = strip_bg_char (&signum_exp);
/* If we must run in the background, but the target can't do it,
error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
/* If we are not asked to run in the bg, then prepare to run in the
foreground, synchronously. */
if (!async_exec && target_can_async_p ())
{
/* Simulate synchronous execution. */
async_disable_stdin ();
}
if (!signum_exp)
error_no_arg (_("signal number"));
@ -1321,10 +1340,15 @@ finish_command (char *arg, int from_tty)
print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
}
proceed_to_finish = 1; /* We want stop_registers, please... */
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
/* If running asynchronously and the target support asynchronous
execution, set things up for the rest of the finish command to be
completed later on, when gdb has detected that the target has
stopped, in fetch_inferior_event. */
stopped, in fetch_inferior_event.
Setup it only after proceed, so that if proceed throws, we don't
set continuation. */
if (target_can_async_p ())
{
arg1 =
@ -1342,9 +1366,6 @@ finish_command (char *arg, int from_tty)
add_continuation (finish_command_continuation, arg1);
}
proceed_to_finish = 1; /* We want stop_registers, please... */
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
/* Do this only if not running asynchronously or if the target
cannot do async execution. Otherwise, complete this command when
the target actually stops, in fetch_inferior_event. */

View file

@ -224,23 +224,13 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
for (i = 1; i < argc; i++)
{
/* We had to set sync_execution = 0 for the mi (well really for Project
Builder's use of the mi - particularly so interrupting would work.
But for console commands to work, we need to initialize it to 1 -
since that is what the cli expects - before running the command,
and then set it back to 0 when we are done. */
sync_execution = 1;
{
struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
if (e.reason < 0)
{
mi_error_message = xstrdup (e.message);
result = MI_CMD_ERROR;
break;
}
}
do_exec_error_cleanups (ALL_CLEANUPS);
sync_execution = 0;
struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
if (e.reason < 0)
{
mi_error_message = xstrdup (e.message);
result = MI_CMD_ERROR;
break;
}
}
mi_remove_notify_hooks ();

View file

@ -7348,6 +7348,8 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
remote_async_ops.to_stop = remote_stop;
remote_async_ops.to_xfer_partial = remote_xfer_partial;
remote_async_ops.to_rcmd = remote_rcmd;
remote_async_ops.to_get_thread_local_address
= remote_get_thread_local_address;
remote_async_ops.to_stratum = process_stratum;
remote_async_ops.to_has_all_memory = 1;
remote_async_ops.to_has_memory = 1;

View file

@ -364,6 +364,42 @@ do_chdir_cleanup (void *old_dir)
}
#endif
/* Do any commands attached to breakpoint we stopped at. Only if we
are always running synchronously. Or if we have just executed a
command that doesn't start the target. */
static void
command_line_handler_continuation (struct continuation_arg *arg)
{
extern int display_time;
extern int display_space;
long time_at_cmd_start = arg->data.longint;
long space_at_cmd_start = arg->next->data.longint;
bpstat_do_actions (&stop_bpstat);
if (display_time)
{
long cmd_time = get_run_time () - time_at_cmd_start;
printf_unfiltered (_("Command execution time: %ld.%06ld\n"),
cmd_time / 1000000, cmd_time % 1000000);
}
if (display_space)
{
#ifdef HAVE_SBRK
char *lim = (char *) sbrk (0);
long space_now = lim - lim_at_start;
long space_diff = space_now - space_at_cmd_start;
printf_unfiltered (_("Space used: %ld (%c%ld for this command)\n"),
space_now,
(space_diff >= 0 ? '+' : '-'),
space_diff);
#endif
}
}
/* Execute the line P as a command.
Pass FROM_TTY as second argument to the defining function. */
@ -374,6 +410,27 @@ execute_command (char *p, int from_tty)
enum language flang;
static int warned = 0;
char *line;
struct continuation_arg *arg1;
struct continuation_arg *arg2;
long time_at_cmd_start;
#ifdef HAVE_SBRK
long space_at_cmd_start = 0;
#endif
extern int display_time;
extern int display_space;
if (target_can_async_p ())
{
time_at_cmd_start = get_run_time ();
if (display_space)
{
#ifdef HAVE_SBRK
char *lim = (char *) sbrk (0);
space_at_cmd_start = lim - lim_at_start;
#endif
}
}
free_all_values ();
@ -470,7 +527,7 @@ execute_command (char *p, int from_tty)
/* FIXME: This should be cacheing the frame and only running when
the frame changes. */
if (target_has_stack)
if (!target_executing && target_has_stack)
{
flang = get_frame_language ();
if (!warned
@ -481,6 +538,24 @@ execute_command (char *p, int from_tty)
warned = 1;
}
}
/* Set things up for this function to be compete later, once the
execution has completed, if we are doing an execution command,
otherwise, just go ahead and finish. */
if (target_can_async_p () && target_executing)
{
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg2 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = arg2;
arg2->next = NULL;
arg1->data.longint = time_at_cmd_start;
#ifdef HAVE_SBRK
arg2->data.longint = space_at_cmd_start;
#endif
add_continuation (command_line_handler_continuation, arg1);
}
}
/* Read commands from `instream' and execute them

View file

@ -164,6 +164,10 @@ tui_command_loop (void *data)
if (result == 0)
{
/* If any exception escaped to here, we better enable
stdin. Otherwise, any command that calls async_disable_stdin,
and then throws, will leave stdin inoperable. */
async_enable_stdin ((void *) 0);
/* FIXME: this should really be a call to a hook that is
interface specific, because interfaces can display the
prompt in their own way. */