Can not resume the parent process over vfork in the foreground while\n\
holding the child stopped. Try \"set detach-on-fork\" or \
\"set schedule-multiple\".\n"));
- return 1;
+ return true;
}
if (!follow_child)
switch_to_thread (child_thr);
}
- return target_follow_fork (follow_child, detach_fork);
+ target_follow_fork (follow_child, detach_fork);
+
+ return false;
}
/* Tell the target to follow the fork we're stopped at. Returns true
target_resume (resume_ptid, step, sig);
- target_commit_resume ();
-
if (target_can_async_p ())
target_async (1);
}
execution_direction)));
}
-/* Calls target_commit_resume on all targets. */
+/* Set process_stratum_target::COMMIT_RESUMED_STATE in all target
+ stacks that have threads executing and don't have threads with
+ pending events. */
static void
-commit_resume_all_targets ()
+maybe_set_commit_resumed_all_targets ()
{
scoped_restore_current_thread restore_thread;
- /* Map between process_target and a representative inferior. This
- is to avoid committing a resume in the same target more than
- once. Resumptions must be idempotent, so this is an
- optimization. */
- std::unordered_map<process_stratum_target *, inferior *> conn_inf;
-
for (inferior *inf : all_non_exited_inferiors ())
- if (inf->has_execution ())
- conn_inf[inf->process_target ()] = inf;
+ {
+ process_stratum_target *proc_target = inf->process_target ();
+
+ if (proc_target->commit_resumed_state)
+ {
+ /* We already set this in a previous iteration, via another
+ inferior sharing the process_stratum target. */
+ continue;
+ }
+
+ /* If the target has no resumed threads, it would be useless to
+ ask it to commit the resumed threads. */
+ if (!proc_target->threads_executing)
+ {
+ infrun_debug_printf ("not requesting commit-resumed for target "
+ "%s, no resumed threads",
+ proc_target->shortname ());
+ continue;
+ }
+
+ /* As an optimization, if a thread from this target has some
+ status to report, handle it before requiring the target to
+ commit its resumed threads: handling the status might lead to
+ resuming more threads. */
+ bool has_thread_with_pending_status = false;
+ for (thread_info *thread : all_non_exited_threads (proc_target))
+ if (thread->resumed && thread->suspend.waitstatus_pending_p)
+ {
+ has_thread_with_pending_status = true;
+ break;
+ }
+
+ if (has_thread_with_pending_status)
+ {
+ infrun_debug_printf ("not requesting commit-resumed for target %s, a"
+ " thread has a pending waitstatus",
+ proc_target->shortname ());
+ continue;
+ }
+
+ switch_to_inferior_no_thread (inf);
+
+ if (target_has_pending_events ())
+ {
+ infrun_debug_printf ("not requesting commit-resumed for target %s, "
+ "target has pending events",
+ proc_target->shortname ());
+ continue;
+ }
+
+ infrun_debug_printf ("enabling commit-resumed for target %s",
+ proc_target->shortname ());
+
+ proc_target->commit_resumed_state = true;
+ }
+}
- for (const auto &ci : conn_inf)
+/* See infrun.h. */
+
+void
+maybe_call_commit_resumed_all_targets ()
+{
+ scoped_restore_current_thread restore_thread;
+
+ for (inferior *inf : all_non_exited_inferiors ())
{
- inferior *inf = ci.second;
+ process_stratum_target *proc_target = inf->process_target ();
+
+ if (!proc_target->commit_resumed_state)
+ continue;
+
switch_to_inferior_no_thread (inf);
- target_commit_resume ();
+
+ infrun_debug_printf ("calling commit_resumed for target %s",
+ proc_target->shortname());
+
+ target_commit_resumed ();
+ }
+}
+
+/* To track nesting of scoped_disable_commit_resumed objects, ensuring
+ that only the outermost one attempts to re-enable
+ commit-resumed. */
+static bool enable_commit_resumed = true;
+
+/* See infrun.h. */
+
+scoped_disable_commit_resumed::scoped_disable_commit_resumed
+ (const char *reason)
+ : m_reason (reason),
+ m_prev_enable_commit_resumed (enable_commit_resumed)
+{
+ infrun_debug_printf ("reason=%s", m_reason);
+
+ enable_commit_resumed = false;
+
+ for (inferior *inf : all_non_exited_inferiors ())
+ {
+ process_stratum_target *proc_target = inf->process_target ();
+
+ if (m_prev_enable_commit_resumed)
+ {
+ /* This is the outermost instance: force all
+ COMMIT_RESUMED_STATE to false. */
+ proc_target->commit_resumed_state = false;
+ }
+ else
+ {
+ /* This is not the outermost instance, we expect
+ COMMIT_RESUMED_STATE to have been cleared by the
+ outermost instance. */
+ gdb_assert (!proc_target->commit_resumed_state);
+ }
+ }
+}
+
+/* See infrun.h. */
+
+void
+scoped_disable_commit_resumed::reset ()
+{
+ if (m_reset)
+ return;
+ m_reset = true;
+
+ infrun_debug_printf ("reason=%s", m_reason);
+
+ gdb_assert (!enable_commit_resumed);
+
+ enable_commit_resumed = m_prev_enable_commit_resumed;
+
+ if (m_prev_enable_commit_resumed)
+ {
+ /* This is the outermost instance, re-enable
+ COMMIT_RESUMED_STATE on the targets where it's possible. */
+ maybe_set_commit_resumed_all_targets ();
+ }
+ else
+ {
+ /* This is not the outermost instance, we expect
+ COMMIT_RESUMED_STATE to still be false. */
+ for (inferior *inf : all_non_exited_inferiors ())
+ {
+ process_stratum_target *proc_target = inf->process_target ();
+ gdb_assert (!proc_target->commit_resumed_state);
+ }
+ }
+}
+
+/* See infrun.h. */
+
+scoped_disable_commit_resumed::~scoped_disable_commit_resumed ()
+{
+ reset ();
+}
+
+/* See infrun.h. */
+
+void
+scoped_disable_commit_resumed::reset_and_commit ()
+{
+ reset ();
+ maybe_call_commit_resumed_all_targets ();
+}
+
+/* See infrun.h. */
+
+scoped_enable_commit_resumed::scoped_enable_commit_resumed
+ (const char *reason)
+ : m_reason (reason),
+ m_prev_enable_commit_resumed (enable_commit_resumed)
+{
+ infrun_debug_printf ("reason=%s", m_reason);
+
+ if (!enable_commit_resumed)
+ {
+ enable_commit_resumed = true;
+
+ /* Re-enable COMMIT_RESUMED_STATE on the targets where it's
+ possible. */
+ maybe_set_commit_resumed_all_targets ();
+
+ maybe_call_commit_resumed_all_targets ();
+ }
+}
+
+/* See infrun.h. */
+
+scoped_enable_commit_resumed::~scoped_enable_commit_resumed ()
+{
+ infrun_debug_printf ("reason=%s", m_reason);
+
+ gdb_assert (enable_commit_resumed);
+
+ enable_commit_resumed = m_prev_enable_commit_resumed;
+
+ if (!enable_commit_resumed)
+ {
+ /* Force all COMMIT_RESUMED_STATE back to false. */
+ for (inferior *inf : all_non_exited_inferiors ())
+ {
+ process_stratum_target *proc_target = inf->process_target ();
+ proc_target->commit_resumed_state = false;
+ }
}
}
cur_thr->prev_pc = regcache_read_pc_protected (regcache);
{
- scoped_restore save_defer_tc = make_scoped_defer_target_commit_resume ();
+ scoped_disable_commit_resumed disable_commit_resumed ("proceeding");
started = start_step_over ();
if (!ecs->wait_some_more)
error (_("Command aborted."));
}
- }
- commit_resume_all_targets ();
+ disable_commit_resumed.reset_and_commit ();
+ }
finish_state.release ();
= make_scoped_restore (&execution_direction,
target_execution_direction ());
+ /* Allow targets to pause their resumed threads while we handle
+ the event. */
+ scoped_disable_commit_resumed disable_commit_resumed ("handling event");
+
if (!do_target_wait (minus_one_ptid, ecs, TARGET_WNOHANG))
- return;
+ {
+ infrun_debug_printf ("do_target_wait returned no event");
+ disable_commit_resumed.reset_and_commit ();
+ return;
+ }
gdb_assert (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
/* No error, don't finish the thread states yet. */
finish_state.release ();
+ disable_commit_resumed.reset_and_commit ();
+
/* This scope is used to ensure that readline callbacks are
reinstalled here. */
}
tp->suspend.waitstatus = *ws;
tp->suspend.waitstatus_pending_p = 1;
- struct regcache *regcache = get_thread_regcache (tp);
- const address_space *aspace = regcache->aspace ();
-
if (ws->kind == TARGET_WAITKIND_STOPPED
&& ws->value.sig == GDB_SIGNAL_TRAP)
{
+ struct regcache *regcache = get_thread_regcache (tp);
+ const address_space *aspace = regcache->aspace ();
CORE_ADDR pc = regcache_read_pc (regcache);
adjust_pc_after_break (tp, &tp->suspend.waitstatus);
inferior_ptid = null_ptid;
target_last_wait_ptid = minus_one_ptid;
- gdb::observers::thread_ptid_changed.attach (infrun_thread_ptid_changed);
- gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested);
- gdb::observers::thread_exit.attach (infrun_thread_thread_exit);
- gdb::observers::inferior_exit.attach (infrun_inferior_exit);
- gdb::observers::inferior_execd.attach (infrun_inferior_execd);
+ gdb::observers::thread_ptid_changed.attach (infrun_thread_ptid_changed,
+ "infrun");
+ gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested,
+ "infrun");
+ gdb::observers::thread_exit.attach (infrun_thread_thread_exit, "infrun");
+ gdb::observers::inferior_exit.attach (infrun_inferior_exit, "infrun");
+ gdb::observers::inferior_execd.attach (infrun_inferior_execd, "infrun");
/* Explicitly create without lookup, since that tries to create a
value with a void typed value, and when we get here, gdbarch