Merge async and sync code paths some more
This patch makes the execution control code use largely the same mechanisms in both sync- and async-capable targets. This means using continuations and use the event loop to react to target events on sync targets as well. The trick is to immediately mark infrun's event loop source after resume instead of calling wait_for_inferior. Then fetch_inferior_event is adjusted to do a blocking wait on sync targets. Tested on x86_64 Fedora 20, native and gdbserver, with and without "maint set target-async off". gdb/ChangeLog: 2015-09-09 Pedro Alves <palves@redhat.com> * breakpoint.c (bpstat_do_actions_1, until_break_command): Don't check whether the target can async. * inf-loop.c (inferior_event_handler): Only call target_async if the target can async. * infcall.c: Include top.h and interps.h. (run_inferior_call): For the interpreter to sync mode while running the infcall. Call wait_sync_command_done instead of wait_for_inferior plus normal_stop. * infcmd.c (prepare_execution_command): Don't check whether the target can async when running in the foreground. (step_1): Delete synchronous case handling. (step_once): Always install a continuation, even in sync mode. (until_next_command, finish_forward): Don't check whether the target can async. (attach_command_post_wait, notice_new_inferior): Always install a continuation, even in sync mode. * infrun.c (mark_infrun_async_event_handler): New function. (proceed): In sync mode, mark infrun's event source instead of waiting for events here. (fetch_inferior_event): If the target can't async, do a blocking wait. (prepare_to_wait): In sync mode, mark infrun's event source. (infrun_async_inferior_event_handler): No longer bail out if the target can't async. * infrun.h (mark_infrun_async_event_handler): New declaration. * linux-nat.c (linux_nat_wait_1): Remove calls to set_sigint_trap/clear_sigint_trap. (linux_nat_terminal_inferior): No longer check whether the target can async. * mi/mi-interp.c (mi_on_sync_execution_done): Update and simplify comment. (mi_execute_command_input_handler): No longer check whether the target is async. Update and simplify comment. * target.c (default_target_wait): New function. * target.h (struct target_ops) <to_wait>: Now defaults to default_target_wait. (default_target_wait): Declare. * top.c (wait_sync_command_done): New function, factored out from ... (maybe_wait_sync_command_done): ... this. * top.h (wait_sync_command_done): Declare. * target-delegates.c: Regenerate.
This commit is contained in:
parent
ea4a7f9986
commit
0b333c5e7d
@ -1,3 +1,48 @@
|
||||
2015-09-09 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* breakpoint.c (bpstat_do_actions_1, until_break_command): Don't
|
||||
check whether the target can async.
|
||||
* inf-loop.c (inferior_event_handler): Only call target_async if
|
||||
the target can async.
|
||||
* infcall.c: Include top.h and interps.h.
|
||||
(run_inferior_call): For the interpreter to sync mode while
|
||||
running the infcall. Call wait_sync_command_done instead of
|
||||
wait_for_inferior plus normal_stop.
|
||||
* infcmd.c (prepare_execution_command): Don't check whether the
|
||||
target can async when running in the foreground.
|
||||
(step_1): Delete synchronous case handling.
|
||||
(step_once): Always install a continuation, even in sync mode.
|
||||
(until_next_command, finish_forward): Don't check whether the
|
||||
target can async.
|
||||
(attach_command_post_wait, notice_new_inferior): Always install a
|
||||
continuation, even in sync mode.
|
||||
* infrun.c (mark_infrun_async_event_handler): New function.
|
||||
(proceed): In sync mode, mark infrun's event source instead of
|
||||
waiting for events here.
|
||||
(fetch_inferior_event): If the target can't async, do a blocking
|
||||
wait.
|
||||
(prepare_to_wait): In sync mode, mark infrun's event source.
|
||||
(infrun_async_inferior_event_handler): No longer bail out if the
|
||||
target can't async.
|
||||
* infrun.h (mark_infrun_async_event_handler): New declaration.
|
||||
* linux-nat.c (linux_nat_wait_1): Remove calls to
|
||||
set_sigint_trap/clear_sigint_trap.
|
||||
(linux_nat_terminal_inferior): No longer check whether the target
|
||||
can async.
|
||||
* mi/mi-interp.c (mi_on_sync_execution_done): Update and simplify
|
||||
comment.
|
||||
(mi_execute_command_input_handler): No longer check whether the
|
||||
target is async. Update and simplify comment.
|
||||
* target.c (default_target_wait): New function.
|
||||
* target.h (struct target_ops) <to_wait>: Now defaults to
|
||||
default_target_wait.
|
||||
(default_target_wait): Declare.
|
||||
* top.c (wait_sync_command_done): New function, factored out from
|
||||
...
|
||||
(maybe_wait_sync_command_done): ... this.
|
||||
* top.h (wait_sync_command_done): Declare.
|
||||
* target-delegates.c: Regenerate.
|
||||
|
||||
2015-09-09 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* nat/linux-btrace.h (struct btrace_target_info) <ptr_bits>: Remove.
|
||||
|
@ -4662,7 +4662,7 @@ bpstat_do_actions_1 (bpstat *bsp)
|
||||
|
||||
if (breakpoint_proceeded)
|
||||
{
|
||||
if (interpreter_async && target_can_async_p ())
|
||||
if (interpreter_async)
|
||||
/* 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. */
|
||||
@ -11588,7 +11588,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
|
||||
be deleted when the target stops. Otherwise, we're already
|
||||
stopped and delete breakpoints via cleanup chain. */
|
||||
|
||||
if (target_can_async_p () && is_running (inferior_ptid))
|
||||
if (is_running (inferior_ptid))
|
||||
{
|
||||
struct until_break_command_continuation_args *args =
|
||||
XNEW (struct until_break_command_continuation_args);
|
||||
|
@ -73,7 +73,7 @@ inferior_event_handler (enum inferior_event_type event_type,
|
||||
/* 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)
|
||||
if (target_has_execution && target_can_async_p ())
|
||||
target_async (0);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@
|
||||
#include "gdbthread.h"
|
||||
#include "event-top.h"
|
||||
#include "observer.h"
|
||||
#include "top.h"
|
||||
#include "interps.h"
|
||||
|
||||
/* If we can't find a function's name from its address,
|
||||
we print this instead. */
|
||||
@ -388,10 +390,13 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
|
||||
ptid_t call_thread_ptid = call_thread->ptid;
|
||||
int saved_sync_execution = sync_execution;
|
||||
int was_running = call_thread->state == THREAD_RUNNING;
|
||||
int saved_interpreter_async = interpreter_async;
|
||||
|
||||
/* Infcalls run synchronously, in the foreground. */
|
||||
if (target_can_async_p ())
|
||||
sync_execution = 1;
|
||||
sync_execution = 1;
|
||||
/* So that we don't print the prompt prematurely in
|
||||
fetch_inferior_event. */
|
||||
interpreter_async = 0;
|
||||
|
||||
call_thread->control.in_infcall = 1;
|
||||
|
||||
@ -404,25 +409,11 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
|
||||
|
||||
TRY
|
||||
{
|
||||
int was_sync = sync_execution;
|
||||
|
||||
proceed (real_pc, GDB_SIGNAL_0);
|
||||
|
||||
/* Inferior function calls are always synchronous, even if the
|
||||
target supports asynchronous execution. Do here what
|
||||
`proceed' itself does in sync mode. */
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
wait_for_inferior ();
|
||||
normal_stop ();
|
||||
/* If GDB was previously in sync execution mode, then ensure
|
||||
that it remains so. normal_stop calls
|
||||
async_enable_stdin, so reset it again here. In other
|
||||
cases, stdin will be re-enabled by
|
||||
inferior_event_handler, when an exception is thrown. */
|
||||
if (was_sync)
|
||||
async_disable_stdin ();
|
||||
}
|
||||
target supports asynchronous execution. */
|
||||
wait_sync_command_done ();
|
||||
}
|
||||
CATCH (e, RETURN_MASK_ALL)
|
||||
{
|
||||
@ -430,6 +421,13 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
/* If GDB was previously in sync execution mode, then ensure that it
|
||||
remains so. normal_stop calls async_enable_stdin, so reset it
|
||||
again here. In other cases, stdin will be re-enabled by
|
||||
inferior_event_handler, when an exception is thrown. */
|
||||
sync_execution = saved_sync_execution;
|
||||
interpreter_async = saved_interpreter_async;
|
||||
|
||||
/* At this point the current thread may have changed. Refresh
|
||||
CALL_THREAD as it could be invalid if its thread has exited. */
|
||||
call_thread = find_thread_ptid (call_thread_ptid);
|
||||
@ -470,8 +468,6 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
|
||||
if (call_thread != NULL)
|
||||
call_thread->control.in_infcall = saved_in_infcall;
|
||||
|
||||
sync_execution = saved_sync_execution;
|
||||
|
||||
return caught_error;
|
||||
}
|
||||
|
||||
|
141
gdb/infcmd.c
141
gdb/infcmd.c
@ -504,13 +504,12 @@ prepare_execution_command (struct target_ops *target, int background)
|
||||
if (background && !target->to_can_async_p (target))
|
||||
error (_("Asynchronous execution not supported on this target."));
|
||||
|
||||
/* If we don't get a request of running in the bg, then we need
|
||||
to simulate synchronous (fg) execution. */
|
||||
if (!background && target->to_can_async_p (target))
|
||||
if (!background)
|
||||
{
|
||||
/* Simulate synchronous execution. Note no cleanup is necessary
|
||||
for this. stdin is re-enabled whenever an error reaches the
|
||||
top level. */
|
||||
/* If we get a request for running in the fg, then we need to
|
||||
simulate synchronous (fg) execution. Note no cleanup is
|
||||
necessary for this. stdin is re-enabled whenever an error
|
||||
reaches the top level. */
|
||||
async_disable_stdin ();
|
||||
}
|
||||
}
|
||||
@ -937,44 +936,15 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
|
||||
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
|
||||
}
|
||||
|
||||
/* In synchronous case, all is well; each step_once call will step once. */
|
||||
if (!target_can_async_p ())
|
||||
{
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
step_once (skip_subroutines, single_inst, count, thread);
|
||||
/* Do only one step for now, before returning control to the event
|
||||
loop. Let the continuation figure out how many other steps we
|
||||
need to do, and handle them one at the time, through
|
||||
step_once. */
|
||||
step_once (skip_subroutines, single_inst, count, thread);
|
||||
|
||||
if (!target_has_execution)
|
||||
break;
|
||||
else
|
||||
{
|
||||
struct thread_info *tp = inferior_thread ();
|
||||
|
||||
if (!tp->control.stop_step || !tp->step_multi)
|
||||
{
|
||||
/* If we stopped for some reason that is not stepping
|
||||
there are no further steps to make. */
|
||||
tp->step_multi = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_cleanups (cleanups);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In the case of an asynchronous target things get complicated;
|
||||
do only one step for now, before returning control to the
|
||||
event loop. Let the continuation figure out how many other
|
||||
steps we need to do, and handle them one at the time, through
|
||||
step_once. */
|
||||
step_once (skip_subroutines, single_inst, count, thread);
|
||||
|
||||
/* We are running, and the continuation is installed. It will
|
||||
disable the longjmp breakpoint as appropriate. */
|
||||
discard_cleanups (cleanups);
|
||||
}
|
||||
/* We are running, and the continuation is installed. It will
|
||||
disable the longjmp breakpoint as appropriate. */
|
||||
discard_cleanups (cleanups);
|
||||
}
|
||||
|
||||
struct step_1_continuation_args
|
||||
@ -1033,6 +1003,7 @@ step_once (int skip_subroutines, int single_inst, int count, int thread)
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
struct step_1_continuation_args *args;
|
||||
/* Don't assume THREAD is a valid thread id. It is set to -1 if
|
||||
the longjmp breakpoint was not required. Use the
|
||||
INFERIOR_PTID thread instead, which is the same thread when
|
||||
@ -1116,21 +1087,15 @@ step_once (int skip_subroutines, int single_inst, int count, int thread)
|
||||
tp->control.stepping_command = 1;
|
||||
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
|
||||
|
||||
/* For async targets, register a continuation to do any
|
||||
additional steps. For sync targets, the caller will handle
|
||||
further stepping. */
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
struct step_1_continuation_args *args =
|
||||
XNEW (struct step_1_continuation_args);
|
||||
/* Register a continuation to do any additional steps. */
|
||||
args = XNEW (struct step_1_continuation_args);
|
||||
args = xmalloc (sizeof (*args));
|
||||
args->skip_subroutines = skip_subroutines;
|
||||
args->single_inst = single_inst;
|
||||
args->count = count;
|
||||
args->thread = thread;
|
||||
|
||||
args->skip_subroutines = skip_subroutines;
|
||||
args->single_inst = single_inst;
|
||||
args->count = count;
|
||||
args->thread = thread;
|
||||
|
||||
add_intermediate_continuation (tp, step_1_continuation, args, xfree);
|
||||
}
|
||||
add_intermediate_continuation (tp, step_1_continuation, args, xfree);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1442,7 +1407,7 @@ until_next_command (int from_tty)
|
||||
|
||||
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
|
||||
|
||||
if (target_can_async_p () && is_running (inferior_ptid))
|
||||
if (is_running (inferior_ptid))
|
||||
{
|
||||
struct until_next_continuation_args *cont_args;
|
||||
|
||||
@ -1801,8 +1766,6 @@ finish_forward (struct symbol *function, struct frame_info *frame)
|
||||
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
|
||||
|
||||
discard_cleanups (old_chain);
|
||||
if (!target_can_async_p ())
|
||||
do_all_continuations (0);
|
||||
}
|
||||
|
||||
/* "finish": Set a temporary breakpoint at the place the selected
|
||||
@ -2532,8 +2495,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
|
||||
/* The user requested a plain `attach', so be sure to leave
|
||||
the inferior stopped. */
|
||||
|
||||
if (target_can_async_p ())
|
||||
async_enable_stdin ();
|
||||
async_enable_stdin ();
|
||||
|
||||
/* At least the current thread is already stopped. */
|
||||
|
||||
@ -2663,6 +2625,7 @@ attach_command (char *args, int from_tty)
|
||||
E.g. Mach 3 or GNU hurd. */
|
||||
if (!target_attach_no_wait)
|
||||
{
|
||||
struct attach_command_continuation_args *a;
|
||||
struct inferior *inferior = current_inferior ();
|
||||
|
||||
/* Careful here. See comments in inferior.h. Basically some
|
||||
@ -2672,25 +2635,19 @@ attach_command (char *args, int from_tty)
|
||||
STOP_QUIETLY_NO_SIGSTOP is for. */
|
||||
inferior->control.stop_soon = STOP_QUIETLY_NO_SIGSTOP;
|
||||
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
/* sync_execution mode. Wait for stop. */
|
||||
struct attach_command_continuation_args *a;
|
||||
/* sync_execution mode. Wait for stop. */
|
||||
a = XNEW (struct attach_command_continuation_args);
|
||||
a->args = xstrdup (args);
|
||||
a->from_tty = from_tty;
|
||||
a->async_exec = async_exec;
|
||||
add_inferior_continuation (attach_command_continuation, a,
|
||||
attach_command_continuation_free_args);
|
||||
/* Done with ARGS. */
|
||||
do_cleanups (args_chain);
|
||||
|
||||
a = XNEW (struct attach_command_continuation_args);
|
||||
a->args = xstrdup (args);
|
||||
a->from_tty = from_tty;
|
||||
a->async_exec = async_exec;
|
||||
add_inferior_continuation (attach_command_continuation, a,
|
||||
attach_command_continuation_free_args);
|
||||
|
||||
/* Done with ARGS. */
|
||||
do_cleanups (args_chain);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
wait_for_inferior ();
|
||||
if (!target_is_async_p ())
|
||||
mark_infrun_async_event_handler ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Done with ARGS. */
|
||||
@ -2731,6 +2688,7 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
|
||||
|
||||
if (is_executing (inferior_ptid))
|
||||
{
|
||||
struct attach_command_continuation_args *a;
|
||||
struct inferior *inferior = current_inferior ();
|
||||
|
||||
/* We're going to install breakpoints, and poke at memory,
|
||||
@ -2741,22 +2699,15 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
|
||||
inferior->control.stop_soon = STOP_QUIETLY_REMOTE;
|
||||
|
||||
/* Wait for stop before proceeding. */
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
struct attach_command_continuation_args *a;
|
||||
a = XNEW (struct attach_command_continuation_args);
|
||||
a->args = xstrdup ("");
|
||||
a->from_tty = from_tty;
|
||||
a->async_exec = async_exec;
|
||||
add_inferior_continuation (attach_command_continuation, a,
|
||||
attach_command_continuation_free_args);
|
||||
|
||||
a = XNEW (struct attach_command_continuation_args);
|
||||
a->args = xstrdup ("");
|
||||
a->from_tty = from_tty;
|
||||
a->async_exec = async_exec;
|
||||
add_inferior_continuation (attach_command_continuation, a,
|
||||
attach_command_continuation_free_args);
|
||||
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
else
|
||||
wait_for_inferior ();
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
async_exec = leave_running;
|
||||
|
37
gdb/infrun.c
37
gdb/infrun.c
@ -131,6 +131,14 @@ infrun_async (int enable)
|
||||
}
|
||||
}
|
||||
|
||||
/* See infrun.h. */
|
||||
|
||||
void
|
||||
mark_infrun_async_event_handler (void)
|
||||
{
|
||||
mark_async_event_handler (infrun_async_inferior_event_token);
|
||||
}
|
||||
|
||||
/* When set, stop the 'step' command if we enter a function which has
|
||||
no line number information. The normal behavior is that we step
|
||||
over such function. */
|
||||
@ -3094,15 +3102,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
|
||||
|
||||
discard_cleanups (old_chain);
|
||||
|
||||
/* Wait for it to stop (if not standalone)
|
||||
and in any case decode why it stopped, and act accordingly. */
|
||||
/* Do this only if we are not using the event loop, or if the target
|
||||
does not support asynchronous execution. */
|
||||
/* Tell the event loop to wait for it to stop. If the target
|
||||
supports asynchronous execution, it'll do this from within
|
||||
target_resume. */
|
||||
if (!target_can_async_p ())
|
||||
{
|
||||
wait_for_inferior ();
|
||||
normal_stop ();
|
||||
}
|
||||
mark_async_event_handler (infrun_async_inferior_event_token);
|
||||
}
|
||||
|
||||
|
||||
@ -3766,7 +3770,8 @@ fetch_inferior_event (void *client_data)
|
||||
make_cleanup_restore_integer (&execution_direction);
|
||||
execution_direction = target_execution_direction ();
|
||||
|
||||
ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, TARGET_WNOHANG);
|
||||
ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws,
|
||||
target_can_async_p () ? TARGET_WNOHANG : 0);
|
||||
|
||||
if (debug_infrun)
|
||||
print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
|
||||
@ -7520,10 +7525,10 @@ prepare_to_wait (struct execution_control_state *ecs)
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: prepare_to_wait\n");
|
||||
|
||||
/* This is the old end of the while loop. Let everybody know we
|
||||
want to wait for the inferior some more and get called again
|
||||
soon. */
|
||||
ecs->wait_some_more = 1;
|
||||
|
||||
if (!target_is_async_p ())
|
||||
mark_infrun_async_event_handler ();
|
||||
}
|
||||
|
||||
/* We are done with the step range of a step/next/si/ni command.
|
||||
@ -8816,14 +8821,6 @@ static const struct internalvar_funcs siginfo_funcs =
|
||||
static void
|
||||
infrun_async_inferior_event_handler (gdb_client_data data)
|
||||
{
|
||||
/* If the target is closed while this event source is marked, we
|
||||
will reach here without execution, or a target to call
|
||||
target_wait on, which is an error. Instead of tracking whether
|
||||
the target has been popped already, or whether we do have threads
|
||||
with pending statutes, simply ignore the event. */
|
||||
if (!target_is_async_p ())
|
||||
return;
|
||||
|
||||
inferior_event_handler (INF_REG_EVENT, NULL);
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,10 @@ enum gdb_signal gdb_signal_from_command (int num);
|
||||
/* Enables/disables infrun's async event source in the event loop. */
|
||||
extern void infrun_async (int enable);
|
||||
|
||||
/* Call infrun's event handler the next time through the event
|
||||
loop. */
|
||||
extern void mark_infrun_async_event_handler (void);
|
||||
|
||||
/* The global queue of threads that need to do a step-over operation
|
||||
to get past e.g., a breakpoint. */
|
||||
extern struct thread_info *step_over_queue_head;
|
||||
|
@ -3442,12 +3442,6 @@ linux_nat_wait_1 (struct target_ops *ops,
|
||||
target_pid_to_str (lp->ptid));
|
||||
}
|
||||
|
||||
if (!target_is_async_p ())
|
||||
{
|
||||
/* Causes SIGINT to be passed on to the attached process. */
|
||||
set_sigint_trap ();
|
||||
}
|
||||
|
||||
/* But if we don't find a pending event, we'll have to wait. Always
|
||||
pull all events out of the kernel. We'll randomly select an
|
||||
event LWP out of all that have events, to prevent starvation. */
|
||||
@ -3518,9 +3512,6 @@ linux_nat_wait_1 (struct target_ops *ops,
|
||||
|
||||
ourstatus->kind = TARGET_WAITKIND_NO_RESUMED;
|
||||
|
||||
if (!target_is_async_p ())
|
||||
clear_sigint_trap ();
|
||||
|
||||
restore_child_signals_mask (&prev_mask);
|
||||
return minus_one_ptid;
|
||||
}
|
||||
@ -3546,9 +3537,6 @@ linux_nat_wait_1 (struct target_ops *ops,
|
||||
sigsuspend (&suspend_mask);
|
||||
}
|
||||
|
||||
if (!target_is_async_p ())
|
||||
clear_sigint_trap ();
|
||||
|
||||
gdb_assert (lp);
|
||||
|
||||
status = lp->status;
|
||||
@ -4629,17 +4617,6 @@ static int async_terminal_is_ours = 1;
|
||||
static void
|
||||
linux_nat_terminal_inferior (struct target_ops *self)
|
||||
{
|
||||
/* Like target_terminal_inferior, use target_can_async_p, not
|
||||
target_is_async_p, since at this point the target is not async
|
||||
yet. If it can async, then we know it will become async prior to
|
||||
resume. */
|
||||
if (!target_can_async_p ())
|
||||
{
|
||||
/* Async mode is disabled. */
|
||||
child_terminal_inferior (self);
|
||||
return;
|
||||
}
|
||||
|
||||
child_terminal_inferior (self);
|
||||
|
||||
/* Calls to target_terminal_*() are meant to be idempotent. */
|
||||
|
@ -309,16 +309,8 @@ mi_execute_command_wrapper (const char *cmd)
|
||||
static void
|
||||
mi_on_sync_execution_done (void)
|
||||
{
|
||||
/* MI generally prints a prompt after a command, indicating it's
|
||||
ready for further input. However, due to an historical wart, if
|
||||
MI async, and a (CLI) synchronous command was issued, then we
|
||||
will print the prompt right after printing "^running", even if we
|
||||
cannot actually accept any input until the target stops. See
|
||||
mi_on_resume. However, if the target is async but MI is sync,
|
||||
then we need to output the MI prompt now, to replicate gdb's
|
||||
behavior when neither the target nor MI are async. (Note this
|
||||
observer is only called by the asynchronous target event handling
|
||||
code.) */
|
||||
/* If MI is sync, then output the MI prompt now, indicating we're
|
||||
ready for further input. */
|
||||
if (!mi_async_p ())
|
||||
{
|
||||
fputs_unfiltered ("(gdb) \n", raw_stdout);
|
||||
@ -333,20 +325,12 @@ mi_execute_command_input_handler (char *cmd)
|
||||
{
|
||||
mi_execute_command_wrapper (cmd);
|
||||
|
||||
/* MI generally prints a prompt after a command, indicating it's
|
||||
ready for further input. However, due to an historical wart, if
|
||||
MI is async, and a synchronous command was issued, then we will
|
||||
print the prompt right after printing "^running", even if we
|
||||
cannot actually accept any input until the target stops. See
|
||||
mi_on_resume.
|
||||
|
||||
If MI is not async, then we print the prompt when the command
|
||||
finishes. If the target is sync, that means output the prompt
|
||||
now, as in that case executing a command doesn't return until the
|
||||
command is done. However, if the target is async, we go back to
|
||||
the event loop and output the prompt in the
|
||||
'synchronous_command_done' observer. */
|
||||
if (!target_is_async_p () || !sync_execution)
|
||||
/* Print a prompt, indicating we're ready for further input, unless
|
||||
we just started a synchronous command. In that case, we're about
|
||||
to go back to the event loop and will output the prompt in the
|
||||
'synchronous_command_done' observer when the target next
|
||||
stops. */
|
||||
if (!sync_execution)
|
||||
{
|
||||
fputs_unfiltered ("(gdb) \n", raw_stdout);
|
||||
gdb_flush (raw_stdout);
|
||||
|
@ -116,12 +116,6 @@ delegate_wait (struct target_ops *self, ptid_t arg1, struct target_waitstatus *a
|
||||
return self->to_wait (self, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
static ptid_t
|
||||
tdefault_wait (struct target_ops *self, ptid_t arg1, struct target_waitstatus *arg2, int arg3)
|
||||
{
|
||||
noprocess ();
|
||||
}
|
||||
|
||||
static ptid_t
|
||||
debug_wait (struct target_ops *self, ptid_t arg1, struct target_waitstatus *arg2, int arg3)
|
||||
{
|
||||
@ -4251,7 +4245,7 @@ install_dummy_methods (struct target_ops *ops)
|
||||
ops->to_detach = tdefault_detach;
|
||||
ops->to_disconnect = tdefault_disconnect;
|
||||
ops->to_resume = tdefault_resume;
|
||||
ops->to_wait = tdefault_wait;
|
||||
ops->to_wait = default_target_wait;
|
||||
ops->to_fetch_registers = tdefault_fetch_registers;
|
||||
ops->to_store_registers = tdefault_store_registers;
|
||||
ops->to_prepare_to_store = tdefault_prepare_to_store;
|
||||
|
11
gdb/target.c
11
gdb/target.c
@ -2233,6 +2233,17 @@ target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
|
||||
return (current_target.to_wait) (¤t_target, ptid, status, options);
|
||||
}
|
||||
|
||||
/* See target.h. */
|
||||
|
||||
ptid_t
|
||||
default_target_wait (struct target_ops *ops,
|
||||
ptid_t ptid, struct target_waitstatus *status,
|
||||
int options)
|
||||
{
|
||||
status->kind = TARGET_WAITKIND_IGNORE;
|
||||
return minus_one_ptid;
|
||||
}
|
||||
|
||||
char *
|
||||
target_pid_to_str (ptid_t ptid)
|
||||
{
|
||||
|
@ -471,7 +471,7 @@ struct target_ops
|
||||
ptid_t (*to_wait) (struct target_ops *,
|
||||
ptid_t, struct target_waitstatus *,
|
||||
int TARGET_DEBUG_PRINTER (target_debug_print_options))
|
||||
TARGET_DEFAULT_NORETURN (noprocess ());
|
||||
TARGET_DEFAULT_FUNC (default_target_wait);
|
||||
void (*to_fetch_registers) (struct target_ops *, struct regcache *, int)
|
||||
TARGET_DEFAULT_IGNORE ();
|
||||
void (*to_store_registers) (struct target_ops *, struct regcache *, int)
|
||||
@ -1327,6 +1327,13 @@ extern void target_resume (ptid_t ptid, int step, enum gdb_signal signal);
|
||||
extern ptid_t target_wait (ptid_t ptid, struct target_waitstatus *status,
|
||||
int options);
|
||||
|
||||
/* The default target_ops::to_wait implementation. */
|
||||
|
||||
extern ptid_t default_target_wait (struct target_ops *ops,
|
||||
ptid_t ptid,
|
||||
struct target_waitstatus *status,
|
||||
int options);
|
||||
|
||||
/* Fetch at least register REGNO, or all regs if regno == -1. No result. */
|
||||
|
||||
extern void target_fetch_registers (struct regcache *regcache, int regno);
|
||||
|
16
gdb/top.c
16
gdb/top.c
@ -367,6 +367,16 @@ check_frame_language_change (void)
|
||||
|
||||
/* See top.h. */
|
||||
|
||||
void
|
||||
wait_sync_command_done (void)
|
||||
{
|
||||
while (gdb_do_one_event () >= 0)
|
||||
if (!sync_execution)
|
||||
break;
|
||||
}
|
||||
|
||||
/* See top.h. */
|
||||
|
||||
void
|
||||
maybe_wait_sync_command_done (int was_sync)
|
||||
{
|
||||
@ -375,11 +385,7 @@ maybe_wait_sync_command_done (int was_sync)
|
||||
just ran a synchronous command that started the target, wait
|
||||
for that command to end. */
|
||||
if (!interpreter_async && !was_sync && sync_execution)
|
||||
{
|
||||
while (gdb_do_one_event () >= 0)
|
||||
if (!sync_execution)
|
||||
break;
|
||||
}
|
||||
wait_sync_command_done ();
|
||||
}
|
||||
|
||||
/* Execute the line P as a command, in the current user context.
|
||||
|
@ -50,6 +50,9 @@ extern void execute_command (char *, int);
|
||||
|
||||
extern void maybe_wait_sync_command_done (int was_sync);
|
||||
|
||||
/* Wait for a synchronous execution command to end. */
|
||||
extern void wait_sync_command_done (void);
|
||||
|
||||
extern void check_frame_language_change (void);
|
||||
|
||||
/* Prepare for execution of a command.
|
||||
|
Loading…
Reference in New Issue
Block a user