static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc);
-static void resume (gdb_signal sig);
+static void resume (gdb_signal sig, bool commit = true);
/* Asynchronous signal handler registered as event loop source for
when we have pending events ready to be passed to the core. */
ecs->ptid = tp->ptid;
}
-static void keep_going_pass_signal (struct execution_control_state *ecs);
+static void keep_going_pass_signal (struct execution_control_state *ecs,
+ bool commit = true);
static void prepare_to_wait (struct execution_control_state *ecs);
static int keep_going_stepped_thread (struct thread_info *tp);
static step_over_what thread_still_needs_step_over (struct thread_info *tp);
bookkeeping. */
static void
-do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig)
+do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig,
+ bool commit)
{
struct thread_info *tp = inferior_thread ();
target_resume (resume_ptid, step, sig);
- target_commit_resume ();
+ if (commit)
+ target_commit_resume ();
+ else
+ current_top_target ()->pending_commit_resume = true;
}
/* Resume the inferior. SIG is the signal to give the inferior
call 'resume', which handles exceptions. */
static void
-resume_1 (enum gdb_signal sig)
+resume_1 (enum gdb_signal sig, bool commit)
{
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = regcache->arch ();
insert_breakpoints ();
resume_ptid = internal_resume_ptid (user_step);
- do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
+ do_target_resume (resume_ptid, 0, GDB_SIGNAL_0, commit);
tp->resumed = 1;
return;
}
gdb_assert (pc_in_thread_step_range (pc, tp));
}
- do_target_resume (resume_ptid, step, sig);
+ do_target_resume (resume_ptid, step, sig, commit);
tp->resumed = 1;
}
rolls back state on error. */
static void
-resume (gdb_signal sig)
+resume (gdb_signal sig, bool commit)
{
try
{
- resume_1 (sig);
+ resume_1 (sig, commit);
}
catch (const gdb_exception &ex)
{
static void end_stepping_range (struct execution_control_state *ecs);
static void stop_waiting (struct execution_control_state *ecs);
-static void keep_going (struct execution_control_state *ecs);
+static void keep_going (struct execution_control_state *ecs,
+ bool commit = true);
static void process_event_stop_test (struct execution_control_state *ecs);
static int switch_back_to_stepped_thread (struct execution_control_state *ecs);
int cmd_done = 0;
ptid_t waiton_ptid = minus_one_ptid;
- memset (ecs, 0, sizeof (*ecs));
-
/* Events are always processed with the main UI as current UI. This
way, warnings, debug output, etc. are always consistently sent to
the main console. */
= make_scoped_restore (&execution_direction,
target_execution_direction ());
- 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);
+ int iter = 0;
+ while (true)
+ {
+ memset (ecs, 0, sizeof (*ecs));
- /* If an error happens while handling the event, propagate GDB's
- knowledge of the executing state to the frontend/user running
- state. */
- ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid;
- scoped_finish_thread_state finish_state (finish_ptid);
+ ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws,
+ target_can_async_p () ? TARGET_WNOHANG : 0);
+ if (ecs->ws.kind == TARGET_WAITKIND_IGNORE
+ || ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED)
+ break;
- /* Get executed before scoped_restore_current_thread above to apply
- still for the thread which has thrown the exception. */
- auto defer_bpstat_clear
- = make_scope_exit (bpstat_clear_actions);
- auto defer_delete_threads
- = make_scope_exit (delete_just_stopped_threads_infrun_breakpoints);
+ if (debug_infrun)
+ print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
- /* Now figure out what to do with the result of the result. */
- handle_inferior_event (ecs);
+ /* If an error happens while handling the event, propagate GDB's
+ knowledge of the executing state to the frontend/user running
+ state. */
+ ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid;
+ scoped_finish_thread_state finish_state (finish_ptid);
- if (!ecs->wait_some_more)
- {
- struct inferior *inf = find_inferior_ptid (ecs->ptid);
- int should_stop = 1;
- struct thread_info *thr = ecs->event_thread;
+ /* Get executed before scoped_restore_current_thread above to apply
+ still for the thread which has thrown the exception. */
+ auto defer_bpstat_clear
+ = make_scope_exit (bpstat_clear_actions);
+ auto defer_delete_threads
+ = make_scope_exit (delete_just_stopped_threads_infrun_breakpoints);
- delete_just_stopped_threads_infrun_breakpoints ();
+ /* Now figure out what to do with the result of the result. */
+ handle_inferior_event (ecs);
- if (thr != NULL)
+ if (!ecs->wait_some_more)
{
- struct thread_fsm *thread_fsm = thr->thread_fsm;
+ struct inferior *inf = find_inferior_ptid (ecs->ptid);
+ int should_stop = 1;
+ struct thread_info *thr = ecs->event_thread;
- if (thread_fsm != NULL)
- should_stop = thread_fsm->should_stop (thr);
- }
+ delete_just_stopped_threads_infrun_breakpoints ();
- if (!should_stop)
- {
- keep_going (ecs);
- }
- else
- {
- bool should_notify_stop = true;
- int proceeded = 0;
-
- clean_up_just_stopped_threads_fsms (ecs);
+ if (thr != NULL)
+ {
+ struct thread_fsm *thread_fsm = thr->thread_fsm;
- if (thr != NULL && thr->thread_fsm != NULL)
- should_notify_stop = thr->thread_fsm->should_notify_stop ();
+ if (thread_fsm != NULL)
+ should_stop = thread_fsm->should_stop (thr);
+ }
- if (should_notify_stop)
+ if (!should_stop)
{
- /* We may not find an inferior if this was a process exit. */
- if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
- proceeded = normal_stop ();
+ keep_going (ecs);
}
-
- if (!proceeded)
+ else
{
- inferior_event_handler (INF_EXEC_COMPLETE, NULL);
- cmd_done = 1;
+ bool should_notify_stop = true;
+ int proceeded = 0;
+
+ clean_up_just_stopped_threads_fsms (ecs);
+
+ if (thr != NULL && thr->thread_fsm != NULL)
+ should_notify_stop = thr->thread_fsm->should_notify_stop ();
+
+ if (should_notify_stop)
+ {
+ /* We may not find an inferior if this was a process exit. */
+ if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
+ proceeded = normal_stop ();
+ }
+
+ if (!proceeded)
+ {
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ cmd_done = 1;
+ }
}
}
- }
- defer_delete_threads.release ();
- defer_bpstat_clear.release ();
+ defer_delete_threads.release ();
+ defer_bpstat_clear.release ();
- /* No error, don't finish the thread states yet. */
- finish_state.release ();
+ /* No error, don't finish the thread states yet. */
+ finish_state.release ();
+
+ iter++;
+ }
+
+ if (current_top_target ()->pending_commit_resume)
+ current_top_target ()->commit_resume ();
/* This scope is used to ensure that readline callbacks are
reinstalled here. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no stepping, continue\n");
/* Likewise if we aren't even stepping. */
- keep_going (ecs);
+ keep_going (ecs, false /* don't commit */);
return;
}
tp->resumed = 1;
resume_ptid = internal_resume_ptid (tp->control.stepping_command);
- do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
+ do_target_resume (resume_ptid, 0, GDB_SIGNAL_0, true);
}
else
{
signal is set to nopass. */
static void
-keep_going_pass_signal (struct execution_control_state *ecs)
+keep_going_pass_signal (struct execution_control_state *ecs, bool commit)
{
gdb_assert (ecs->event_thread->ptid == inferior_ptid);
gdb_assert (!ecs->event_thread->resumed);
ecs->event_thread->control.trap_expected = (remove_bp || remove_wps);
- resume (ecs->event_thread->suspend.stop_signal);
+ resume (ecs->event_thread->suspend.stop_signal, commit);
}
prepare_to_wait (ecs);
resuming part; waiting for the next event is done elsewhere. */
static void
-keep_going (struct execution_control_state *ecs)
+keep_going (struct execution_control_state *ecs, bool commit)
{
if (ecs->event_thread->control.trap_expected
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
if (!signal_program[ecs->event_thread->suspend.stop_signal])
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
- keep_going_pass_signal (ecs);
+ keep_going_pass_signal (ecs, commit);
}
/* This function normally comes after a resume, before