Skip to content

Commit 408f668

Browse files
committed
detach in all-stop with threads running
A following patch will add a testcase that has a number of threads constantly stepping over a breakpoint, and then has GDB detach the process, while threads are running. If we have more than one inferior running, and we detach from just one of the inferiors, we expect that the remaining inferior continues running. However, in all-stop, if GDB needs to pause the target for the detach, nothing is re-resuming the other inferiors after the detach. "info threads" shows the threads as running, but they really aren't. This fixes it. gdb/ChangeLog: * infcmd.c (detach_command): Hold strong reference to target, and if all-stop on entry, restart threads on exit. * infrun.c (switch_back_to_stepped_thread): Factor out bits to ... (restart_stepped_thread): ... this new function. Also handle trap_expected. (restart_after_all_stop_detach): New function. * infrun.h (restart_after_all_stop_detach): Declare.
1 parent ac7d717 commit 408f668

File tree

4 files changed

+138
-52
lines changed

4 files changed

+138
-52
lines changed

gdb/ChangeLog

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2021-02-03 Pedro Alves <pedro@palves.net>
2+
3+
* infcmd.c (detach_command): Hold strong reference to target, and
4+
if all-stop on entry, restart threads on exit.
5+
* infrun.c (switch_back_to_stepped_thread): Factor out bits to ...
6+
(restart_stepped_thread): ... this new function. Also handle
7+
trap_expected.
8+
(restart_after_all_stop_detach): New function.
9+
* infrun.h (restart_after_all_stop_detach): Declare.
10+
111
2021-02-03 Pedro Alves <pedro@palves.net>
212

313
* infrun.c (struct step_over_info): Initialize fields.

gdb/infcmd.c

+13
Original file line numberDiff line numberDiff line change
@@ -2750,6 +2750,16 @@ detach_command (const char *args, int from_tty)
27502750

27512751
disconnect_tracing ();
27522752

2753+
/* Hold a strong reference to the target while (maybe)
2754+
detaching the parent. Otherwise detaching could close the
2755+
target. */
2756+
auto target_ref
2757+
= target_ops_ref::new_reference (current_inferior ()->process_target ());
2758+
2759+
/* Save this before detaching, since detaching may unpush the
2760+
process_stratum target. */
2761+
bool was_non_stop_p = target_is_non_stop_p ();
2762+
27532763
target_detach (current_inferior (), from_tty);
27542764

27552765
/* The current inferior process was just detached successfully. Get
@@ -2766,6 +2776,9 @@ detach_command (const char *args, int from_tty)
27662776

27672777
if (deprecated_detach_hook)
27682778
deprecated_detach_hook ();
2779+
2780+
if (!was_non_stop_p)
2781+
restart_after_all_stop_detach (as_process_stratum_target (target_ref.get ()));
27692782
}
27702783

27712784
/* Disconnect from the current target without resuming it (leaving it

gdb/infrun.c

+111-52
Original file line numberDiff line numberDiff line change
@@ -7110,6 +7110,9 @@ process_event_stop_test (struct execution_control_state *ecs)
71107110
keep_going (ecs);
71117111
}
71127112

7113+
static bool restart_stepped_thread (process_stratum_target *resume_target,
7114+
ptid_t resume_ptid);
7115+
71137116
/* In all-stop mode, if we're currently stepping but have stopped in
71147117
some other thread, we may need to switch back to the stepped
71157118
thread. Returns true we set the inferior running, false if we left
@@ -7120,8 +7123,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
71207123
{
71217124
if (!target_is_non_stop_p ())
71227125
{
7123-
struct thread_info *stepping_thread;
7124-
71257126
/* If any thread is blocked on some internal breakpoint, and we
71267127
simply need to step over that breakpoint to get it going
71277128
again, do that first. */
@@ -7184,78 +7185,136 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
71847185
if (!signal_program[ecs->event_thread->suspend.stop_signal])
71857186
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
71867187

7187-
/* Do all pending step-overs before actually proceeding with
7188-
step/next/etc. */
7189-
if (start_step_over ())
7188+
if (restart_stepped_thread (ecs->target, ecs->ptid))
71907189
{
71917190
prepare_to_wait (ecs);
71927191
return true;
71937192
}
71947193

7195-
/* Look for the stepping/nexting thread. */
7196-
stepping_thread = NULL;
7194+
switch_to_thread (ecs->event_thread);
7195+
}
71977196

7198-
for (thread_info *tp : all_non_exited_threads ())
7199-
{
7200-
switch_to_thread_no_regs (tp);
7197+
return false;
7198+
}
72017199

7202-
/* Ignore threads of processes the caller is not
7203-
resuming. */
7204-
if (!sched_multi
7205-
&& (tp->inf->process_target () != ecs->target
7206-
|| tp->inf->pid != ecs->ptid.pid ()))
7207-
continue;
7200+
/* Look for the thread that was stepping, and resume it.
7201+
RESUME_TARGET / RESUME_PTID indicate the set of threads the caller
7202+
is resuming. Return true if a thread was started, false
7203+
otherwise. */
72087204

7209-
/* When stepping over a breakpoint, we lock all threads
7210-
except the one that needs to move past the breakpoint.
7211-
If a non-event thread has this set, the "incomplete
7212-
step-over" check above should have caught it earlier. */
7213-
if (tp->control.trap_expected)
7214-
{
7215-
internal_error (__FILE__, __LINE__,
7216-
"[%s] has inconsistent state: "
7217-
"trap_expected=%d\n",
7218-
target_pid_to_str (tp->ptid).c_str (),
7219-
tp->control.trap_expected);
7220-
}
7205+
static bool
7206+
restart_stepped_thread (process_stratum_target *resume_target,
7207+
ptid_t resume_ptid)
7208+
{
7209+
/* Do all pending step-overs before actually proceeding with
7210+
step/next/etc. */
7211+
if (start_step_over ())
7212+
return true;
72217213

7222-
/* Did we find the stepping thread? */
7223-
if (tp->control.step_range_end)
7224-
{
7225-
/* Yep. There should only one though. */
7226-
gdb_assert (stepping_thread == NULL);
7214+
for (thread_info *tp : all_threads_safe ())
7215+
{
7216+
if (tp->state == THREAD_EXITED)
7217+
continue;
7218+
7219+
if (tp->suspend.waitstatus_pending_p)
7220+
continue;
72277221

7228-
/* The event thread is handled at the top, before we
7229-
enter this loop. */
7230-
gdb_assert (tp != ecs->event_thread);
7222+
/* Ignore threads of processes the caller is not
7223+
resuming. */
7224+
if (!sched_multi
7225+
&& (tp->inf->process_target () != resume_target
7226+
|| tp->inf->pid != resume_ptid.pid ()))
7227+
continue;
72317228

7232-
/* If some thread other than the event thread is
7233-
stepping, then scheduler locking can't be in effect,
7234-
otherwise we wouldn't have resumed the current event
7235-
thread in the first place. */
7236-
gdb_assert (!schedlock_applies (tp));
7229+
if (tp->control.trap_expected)
7230+
{
7231+
infrun_debug_printf ("switching back to stepped thread (step-over)");
72377232

7238-
stepping_thread = tp;
7239-
}
7233+
if (keep_going_stepped_thread (tp))
7234+
return true;
72407235
}
7236+
}
7237+
7238+
for (thread_info *tp : all_threads_safe ())
7239+
{
7240+
if (tp->state == THREAD_EXITED)
7241+
continue;
7242+
7243+
if (tp->suspend.waitstatus_pending_p)
7244+
continue;
72417245

7242-
if (stepping_thread != NULL)
7246+
/* Ignore threads of processes the caller is not
7247+
resuming. */
7248+
if (!sched_multi
7249+
&& (tp->inf->process_target () != resume_target
7250+
|| tp->inf->pid != resume_ptid.pid ()))
7251+
continue;
7252+
7253+
/* Did we find the stepping thread? */
7254+
if (tp->control.step_range_end)
72437255
{
7244-
infrun_debug_printf ("switching back to stepped thread");
7256+
infrun_debug_printf ("switching back to stepped thread (stepping)");
72457257

7246-
if (keep_going_stepped_thread (stepping_thread))
7247-
{
7248-
prepare_to_wait (ecs);
7249-
return true;
7250-
}
7258+
if (keep_going_stepped_thread (tp))
7259+
return true;
72517260
}
7252-
7253-
switch_to_thread (ecs->event_thread);
72547261
}
72557262

72567263
return false;
72577264
}
72587265

7266+
/* See infrun.h. */
7267+
7268+
void
7269+
restart_after_all_stop_detach (process_stratum_target *proc_target)
7270+
{
7271+
/* Note we don't check target_is_non_stop_p() here, because the
7272+
current inferior may no longer have a process_stratum target
7273+
pushed, as we just detached. */
7274+
7275+
/* See if we have a THREAD_RUNNING thread that need to be
7276+
re-resumed. If we have any thread that is already executing,
7277+
then we don't need to resume the target -- it is already been
7278+
resumed. With the remote target (in all-stop), it's even
7279+
impossible to issue another resumption if the target is already
7280+
resumed, until the target reports a stop. */
7281+
for (thread_info *thr : all_threads (proc_target))
7282+
{
7283+
if (thr->state != THREAD_RUNNING)
7284+
continue;
7285+
7286+
/* If we have any thread that is already executing, then we
7287+
don't need to resume the target -- it is already been
7288+
resumed. */
7289+
if (thr->executing)
7290+
return;
7291+
7292+
/* If we have a pending event to process, skip resuming the
7293+
target and go straight to processing it. */
7294+
if (thr->resumed && thr->suspend.waitstatus_pending_p)
7295+
return;
7296+
}
7297+
7298+
/* Alright, we need to re-resume the target. If a thread was
7299+
stepping, we need to restart it stepping. */
7300+
if (restart_stepped_thread (proc_target, minus_one_ptid))
7301+
return;
7302+
7303+
/* Otherwise, find the first THREAD_RUNNING thread and resume
7304+
it. */
7305+
for (thread_info *thr : all_threads (proc_target))
7306+
{
7307+
if (thr->state != THREAD_RUNNING)
7308+
continue;
7309+
7310+
execution_control_state ecs;
7311+
reset_ecs (&ecs, thr);
7312+
switch_to_thread (thr);
7313+
keep_going (&ecs);
7314+
return;
7315+
}
7316+
}
7317+
72597318
/* Set a previously stepped thread back to stepping. Returns true on
72607319
success, false if the resume is not possible (e.g., the thread
72617320
vanished). */

gdb/infrun.h

+4
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,8 @@ extern void all_uis_check_sync_execution_done (void);
269269
started or re-started). */
270270
extern void all_uis_on_sync_execution_starting (void);
271271

272+
/* In all-stop, restart the target if it had to be stopped to
273+
detach. */
274+
extern void restart_after_all_stop_detach (process_stratum_target *proc_target);
275+
272276
#endif /* INFRUN_H */

0 commit comments

Comments
 (0)