+/* Handle one event after stopping threads. If the eventing thread
+ reports back any interesting event, we leave it pending. If the
+ eventing thread was in the middle of a displaced step, we
+ cancel/finish it, and unless the thread's inferior is being
+ detached, put the thread back in the step-over chain. Returns true
+ if there are no resumed threads left in the target (thus there's no
+ point in waiting further), false otherwise. */
+
+static bool
+handle_one (const wait_one_event &event)
+{
+ infrun_debug_printf
+ ("%s %s", target_waitstatus_to_string (&event.ws).c_str (),
+ target_pid_to_str (event.ptid).c_str ());
+
+ if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED)
+ {
+ /* All resumed threads exited. */
+ return true;
+ }
+ else if (event.ws.kind == TARGET_WAITKIND_THREAD_EXITED
+ || event.ws.kind == TARGET_WAITKIND_EXITED
+ || event.ws.kind == TARGET_WAITKIND_SIGNALLED)
+ {
+ /* One thread/process exited/signalled. */
+
+ thread_info *t = nullptr;
+
+ /* The target may have reported just a pid. If so, try
+ the first non-exited thread. */
+ if (event.ptid.is_pid ())
+ {
+ int pid = event.ptid.pid ();
+ inferior *inf = find_inferior_pid (event.target, pid);
+ for (thread_info *tp : inf->non_exited_threads ())
+ {
+ t = tp;
+ break;
+ }
+
+ /* If there is no available thread, the event would
+ have to be appended to a per-inferior event list,
+ which does not exist (and if it did, we'd have
+ to adjust run control command to be able to
+ resume such an inferior). We assert here instead
+ of going into an infinite loop. */
+ gdb_assert (t != nullptr);
+
+ infrun_debug_printf
+ ("using %s", target_pid_to_str (t->ptid).c_str ());
+ }
+ else
+ {
+ t = find_thread_ptid (event.target, event.ptid);
+ /* Check if this is the first time we see this thread.
+ Don't bother adding if it individually exited. */
+ if (t == nullptr
+ && event.ws.kind != TARGET_WAITKIND_THREAD_EXITED)
+ t = add_thread (event.target, event.ptid);
+ }
+
+ if (t != nullptr)
+ {
+ /* Set the threads as non-executing to avoid
+ another stop attempt on them. */
+ switch_to_thread_no_regs (t);
+ mark_non_executing_threads (event.target, event.ptid,
+ event.ws);
+ save_waitstatus (t, &event.ws);
+ t->stop_requested = false;
+ }
+ }
+ else
+ {
+ thread_info *t = find_thread_ptid (event.target, event.ptid);
+ if (t == NULL)
+ t = add_thread (event.target, event.ptid);
+
+ t->stop_requested = 0;
+ t->executing = 0;
+ t->resumed = false;
+ t->control.may_range_step = 0;
+
+ /* This may be the first time we see the inferior report
+ a stop. */
+ inferior *inf = find_inferior_ptid (event.target, event.ptid);
+ if (inf->needs_setup)
+ {
+ switch_to_thread_no_regs (t);
+ setup_inferior (0);
+ }
+
+ if (event.ws.kind == TARGET_WAITKIND_STOPPED
+ && event.ws.value.sig == GDB_SIGNAL_0)
+ {
+ /* We caught the event that we intended to catch, so
+ there's no event pending. */
+ t->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
+ t->suspend.waitstatus_pending_p = 0;
+
+ if (displaced_step_finish (t, GDB_SIGNAL_0)
+ == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
+ {
+ /* Add it back to the step-over queue. */
+ infrun_debug_printf
+ ("displaced-step of %s canceled",
+ target_pid_to_str (t->ptid).c_str ());
+
+ t->control.trap_expected = 0;
+ if (!t->inf->detaching)
+ global_thread_step_over_chain_enqueue (t);
+ }
+ }
+ else
+ {
+ enum gdb_signal sig;
+ struct regcache *regcache;
+
+ infrun_debug_printf
+ ("target_wait %s, saving status for %d.%ld.%ld",
+ target_waitstatus_to_string (&event.ws).c_str (),
+ t->ptid.pid (), t->ptid.lwp (), t->ptid.tid ());
+
+ /* Record for later. */
+ save_waitstatus (t, &event.ws);
+
+ sig = (event.ws.kind == TARGET_WAITKIND_STOPPED
+ ? event.ws.value.sig : GDB_SIGNAL_0);
+
+ if (displaced_step_finish (t, sig)
+ == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
+ {
+ /* Add it back to the step-over queue. */
+ t->control.trap_expected = 0;
+ if (!t->inf->detaching)
+ global_thread_step_over_chain_enqueue (t);
+ }
+
+ regcache = get_thread_regcache (t);
+ t->suspend.stop_pc = regcache_read_pc (regcache);
+
+ infrun_debug_printf ("saved stop_pc=%s for %s "
+ "(currently_stepping=%d)",
+ paddress (target_gdbarch (),
+ t->suspend.stop_pc),
+ target_pid_to_str (t->ptid).c_str (),
+ currently_stepping (t));
+ }
+ }
+
+ return false;
+}
+