Implement all-stop on top of a target running non-stop mode

This finally implements user-visible all-stop mode running with the
target_ops backend always in non-stop mode.  This is a stepping stone
towards finer-grained control of threads, being able to do interesting
things like thread groups, associating groups with breakpoints, etc.
From the user's perspective, all-stop mode is really just a special
case of being able to stop and resume specific sets of threads, so it
makes sense to do this step first.

With this, even in all-stop, the target is no longer in charge of
stopping all threads before reporting an event to the core -- the core
takes care of it when it sees fit.  For example, when "next"- or
"step"-ing, we can avoid stopping and resuming all threads at each
internal single-step, and instead only stop all threads when we're
about to present the stop to the user.

The implementation is almost straight forward, as the heavy lifting
has been done already in previous patches.  Basically, we replace
checks for "set non-stop on/off" (the non_stop global), with calls to
a new target_is_non_stop_p function.  In a few places, if "set
non-stop off", we stop all threads explicitly, and in a few other
places we resume all threads explicitly, making use of existing
methods that were added for teaching non-stop to step over breakpoints
without displaced stepping.

This adds a new "maint set target-non-stop on/off/auto" knob that
allows both disabling the feature if we find problems, and
force-enable it for development (useful when teaching a target about
this.  The default is "auto", which means the feature is enabled if a
new target method says it should be enabled.  The patch implements the
method in linux-nat.c, just for illustration, because it still returns
false.  We'll need a few follow up fixes before turning it on by
default.  This is a separate target method from indicating regular
non-stop support, because e.g., while e.g., native linux-nat.c is
close to regression free with all-stop-non-stop (with following
patches will fixing the remaining regressions), remote.c+gdbserver
will still need more fixing, even though it supports "set non-stop
on".

Tested on x86_64 Fedora 20, native, with and without "set displaced
off", and with and without "maint set target-non-stop on"; and also
against gdbserver.

gdb/ChangeLog:
2015-08-07  Pedro Alves  <palves@redhat.com>

	* NEWS: Mention "maint set/show target-non-stop".
	* breakpoint.c (update_global_location_list): Check
	target_is_non_stop_p instead of non_stop.
	* infcmd.c (attach_command_post_wait, attach_command): Likewise.
	* infrun.c (show_can_use_displaced_stepping)
	(can_use_displaced_stepping_p, start_step_over_inferior):
	Likewise.
	(internal_resume_ptid): New function.
	(resume): Use it.
	(proceed): Check target_is_non_stop_p instead of non_stop.  If in
	all-stop mode but the target is always in non-stop mode, start all
	the other threads that are implicitly resumed too.
	(for_each_just_stopped_thread, fetch_inferior_event)
	(adjust_pc_after_break, stop_all_threads): Check
	target_is_non_stop_p instead of non_stop.
	(handle_inferior_event): Likewise.  Handle detach-fork in all-stop
	with the target always in non-stop mode.
	(handle_signal_stop) <random signal>: Check target_is_non_stop_p
	instead of non_stop.
	(switch_back_to_stepped_thread): Check target_is_non_stop_p
	instead of non_stop.
	(keep_going_stepped_thread): Use internal_resume_ptid.
	(stop_waiting): If in all-stop mode, and the target is in non-stop
	mode, stop all threads.
	(keep_going_pass): Likewise, when starting a new in-line step-over
	sequence.
	* linux-nat.c (get_pending_status, select_event_lwp)
	(linux_nat_filter_event, linux_nat_wait_1, linux_nat_wait): Check
	target_is_non_stop_p instead of non_stop.
	(linux_nat_always_non_stop_p): New function.
	(linux_nat_stop): Check target_is_non_stop_p instead of non_stop.
	(linux_nat_add_target): Install linux_nat_always_non_stop_p.
	* target-delegates.c: Regenerate.
	* target.c (target_is_non_stop_p): New function.
	(target_non_stop_enabled, target_non_stop_enabled_1): New globals.
	(maint_set_target_non_stop_command)
	(maint_show_target_non_stop_command): New functions.
	(_initilize_target): Install "maint set/show target-non-stop"
	commands.
	* target.h (struct target_ops) <to_always_non_stop_p>: New field.
	(target_non_stop_enabled): New declaration.
	(target_is_non_stop_p): New declaration.

gdb/doc/ChangeLog:
2015-08-07  Pedro Alves  <palves@redhat.com>

	* gdb.texinfo (Maintenance Commands): Document "maint set/show
	target-non-stop".
This commit is contained in:
Pedro Alves
2015-08-07 17:24:01 +01:00
parent 372316f128
commit fbea99ea8a
11 changed files with 318 additions and 38 deletions

View File

@@ -1630,7 +1630,7 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
fprintf_filtered (file,
_("Debugger's willingness to use displaced stepping "
"to step over breakpoints is %s (currently %s).\n"),
value, non_stop ? "on" : "off");
value, target_is_non_stop_p () ? "on" : "off");
else
fprintf_filtered (file,
_("Debugger's willingness to use displaced stepping "
@@ -1643,7 +1643,8 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
static int
use_displaced_stepping (struct gdbarch *gdbarch)
{
return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop)
return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
&& target_is_non_stop_p ())
|| can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
&& gdbarch_displaced_step_copy_insn_p (gdbarch)
&& find_record_target () == NULL);
@@ -2014,7 +2015,7 @@ start_step_over (void)
because we wouldn't be able to resume anything else until the
target stops again. In non-stop, the resume always resumes
only TP, so it's OK to let the thread resume freely. */
if (!non_stop && !step_what)
if (!target_is_non_stop_p () && !step_what)
continue;
switch_to_thread (tp->ptid);
@@ -2033,7 +2034,7 @@ start_step_over (void)
return 1;
}
if (!non_stop)
if (!target_is_non_stop_p ())
{
/* On all-stop, shouldn't have resumed unless we needed a
step over. */
@@ -2178,6 +2179,25 @@ user_visible_resume_ptid (int step)
return resume_ptid;
}
/* Return a ptid representing the set of threads that we will resume,
in the perspective of the target, assuming run control handling
does not require leaving some threads stopped (e.g., stepping past
breakpoint). USER_STEP indicates whether we're about to start the
target for a stepping command. */
static ptid_t
internal_resume_ptid (int user_step)
{
/* In non-stop, we always control threads individually. Note that
the target may always work in non-stop mode even with "set
non-stop off", in which case user_visible_resume_ptid could
return a wildcard ptid. */
if (target_is_non_stop_p ())
return inferior_ptid;
else
return user_visible_resume_ptid (user_step);
}
/* Wrapper for target_resume, that handles infrun-specific
bookkeeping. */
@@ -2389,7 +2409,7 @@ resume (enum gdb_signal sig)
insert_single_step_breakpoint (gdbarch, aspace, pc);
insert_breakpoints ();
resume_ptid = user_visible_resume_ptid (user_step);
resume_ptid = internal_resume_ptid (user_step);
do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
discard_cleanups (old_cleanups);
tp->resumed = 1;
@@ -2498,12 +2518,7 @@ resume (enum gdb_signal sig)
use singlestep breakpoint. */
gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step));
/* Decide the set of threads to ask the target to resume. Start
by assuming everything will be resumed, than narrow the set
by applying increasingly restricting conditions. */
resume_ptid = user_visible_resume_ptid (user_step);
/* Maybe resume a single thread after all. */
/* Decide the set of threads to ask the target to resume. */
if ((step || thread_has_single_step_breakpoints_set (tp))
&& tp->control.trap_expected)
{
@@ -2514,6 +2529,8 @@ resume (enum gdb_signal sig)
breakpoint if allowed to run. */
resume_ptid = inferior_ptid;
}
else
resume_ptid = internal_resume_ptid (user_step);
if (execution_direction != EXEC_REVERSE
&& step && breakpoint_inserted_here_p (aspace, pc))
@@ -2935,11 +2952,52 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
other thread was already doing one. In either case, don't
resume anything else until the step-over is finished. */
}
else if (started && !non_stop)
else if (started && !target_is_non_stop_p ())
{
/* A new displaced stepping sequence was started. In all-stop,
we can't talk to the target anymore until it next stops. */
}
else if (!non_stop && target_is_non_stop_p ())
{
/* In all-stop, but the target is always in non-stop mode.
Start all other threads that are implicitly resumed too. */
ALL_NON_EXITED_THREADS (tp)
{
/* Ignore threads of processes we're not resuming. */
if (!ptid_match (tp->ptid, resume_ptid))
continue;
if (tp->resumed)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: proceed: [%s] resumed\n",
target_pid_to_str (tp->ptid));
gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p);
continue;
}
if (thread_is_in_step_over_chain (tp))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: proceed: [%s] needs step-over\n",
target_pid_to_str (tp->ptid));
continue;
}
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: proceed: resuming %s\n",
target_pid_to_str (tp->ptid));
reset_ecs (ecs, tp);
switch_to_thread (tp->ptid);
keep_going_pass_signal (ecs);
if (!ecs->wait_some_more)
error ("Command aborted.");
}
}
else if (!tp->resumed && !thread_is_in_step_over_chain (tp))
{
/* The thread wasn't started, and isn't queued, run it now. */
@@ -3151,7 +3209,7 @@ for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid))
return;
if (non_stop)
if (target_is_non_stop_p ())
{
/* If in non-stop mode, only the current thread stopped. */
func (inferior_thread ());
@@ -3632,7 +3690,7 @@ fetch_inferior_event (void *client_data)
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
state. */
if (!non_stop)
if (!target_is_non_stop_p ())
ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
else
ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid);
@@ -3871,7 +3929,8 @@ adjust_pc_after_break (struct thread_info *thread,
to get the "stopped by SW BP and needs adjustment" info out of
the target/kernel (and thus never reach here; see above). */
if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
|| (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
|| (target_is_non_stop_p ()
&& moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
@@ -4148,7 +4207,7 @@ stop_all_threads (void)
ptid_t entry_ptid;
struct cleanup *old_chain;
gdb_assert (non_stop);
gdb_assert (target_is_non_stop_p ());
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n");
@@ -4460,7 +4519,7 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
{
ptid_t mark_ptid;
if (!non_stop)
if (!target_is_non_stop_p ())
mark_ptid = minus_one_ptid;
else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED
|| ecs->ws.kind == TARGET_WAITKIND_EXITED)
@@ -4774,7 +4833,8 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
child = ecs->ws.value.related_pid;
/* In non-stop mode, also resume the other branch. */
if (non_stop && !detach_fork)
if (!detach_fork && (non_stop
|| (sched_multi && target_is_non_stop_p ())))
{
if (follow_child)
switch_to_thread (parent);
@@ -5058,7 +5118,7 @@ finish_step_over (struct execution_control_state *ecs)
clear_step_over_info ();
}
if (!non_stop)
if (!target_is_non_stop_p ())
return 0;
/* Start a new step-over in another thread if there's one that
@@ -5638,15 +5698,17 @@ handle_signal_stop (struct execution_control_state *ecs)
/* Reset trap_expected to ensure breakpoints are re-inserted. */
ecs->event_thread->control.trap_expected = 0;
if (non_stop)
if (target_is_non_stop_p ())
{
/* Either "set non-stop" is "on", or the target is
always in non-stop mode. In this case, we have a bit
more work to do. Resume the current thread, and if
we had paused all threads, restart them while the
signal handler runs. */
keep_going (ecs);
/* The step-over has been canceled temporarily while the
signal handler executes. */
if (was_in_line)
{
/* We had paused all threads, restart them. */
restart_threads (ecs->event_thread);
}
else if (debug_infrun)
@@ -6541,7 +6603,7 @@ process_event_stop_test (struct execution_control_state *ecs)
static int
switch_back_to_stepped_thread (struct execution_control_state *ecs)
{
if (!non_stop)
if (!target_is_non_stop_p ())
{
struct thread_info *tp;
struct thread_info *stepping_thread;
@@ -6632,7 +6694,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
ALL_NON_EXITED_THREADS (tp)
{
/* Ignore threads of processes we're not resuming. */
/* Ignore threads of processes the caller is not
resuming. */
if (!sched_multi
&& ptid_get_pid (tp->ptid) != ptid_get_pid (ecs->ptid))
continue;
@@ -6778,7 +6841,7 @@ keep_going_stepped_thread (struct thread_info *tp)
stop_pc);
tp->resumed = 1;
resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
resume_ptid = internal_resume_ptid (tp->control.stepping_command);
do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
}
else
@@ -7199,6 +7262,11 @@ stop_waiting (struct execution_control_state *ecs)
/* Let callers know we don't want to wait for the inferior anymore. */
ecs->wait_some_more = 0;
/* If all-stop, but the target is always in non-stop mode, stop all
threads now that we're presenting the stop to the user. */
if (!non_stop && target_is_non_stop_p ())
stop_all_threads ();
}
/* Like keep_going, but passes the signal to the inferior, even if the
@@ -7313,7 +7381,7 @@ keep_going_pass_signal (struct execution_control_state *ecs)
insert_breakpoints below, because that removes the breakpoint
we're about to step over, otherwise other threads could miss
it. */
if (step_over_info_valid_p () && non_stop)
if (step_over_info_valid_p () && target_is_non_stop_p ())
stop_all_threads ();
/* Stop stepping if inserting breakpoints fails. */