/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2015 Free Software Foundation, Inc.
+ Copyright (C) 1986-2016 Free Software Foundation, Inc.
This file is part of GDB.
}
}
+/* A cleanup that disables thread create/exit events. */
+
+static void
+disable_thread_events (void *arg)
+{
+ target_thread_events (0);
+}
+
/* See infrun.h. */
void
entry_ptid = inferior_ptid;
old_chain = make_cleanup (switch_to_thread_cleanup, &entry_ptid);
+ target_thread_events (1);
+ make_cleanup (disable_thread_events, NULL);
+
/* Request threads to stop, and then wait for the stops. Because
threads we already know about can spawn more threads while we're
trying to stop them, and we only learn about new threads when we
{
/* All resumed threads exited. */
}
- else if (ws.kind == TARGET_WAITKIND_EXITED
+ else if (ws.kind == TARGET_WAITKIND_THREAD_EXITED
+ || ws.kind == TARGET_WAITKIND_EXITED
|| ws.kind == TARGET_WAITKIND_SIGNALLED)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads done\n");
}
+/* Handle a TARGET_WAITKIND_NO_RESUMED event. */
+
+static int
+handle_no_resumed (struct execution_control_state *ecs)
+{
+ struct inferior *inf;
+ struct thread_info *thread;
+
+ if (target_can_async_p () && !sync_execution)
+ {
+ /* There were no unwaited-for children left in the target, but,
+ we're not synchronously waiting for events either. Just
+ ignore. */
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: TARGET_WAITKIND_NO_RESUMED " "(ignoring: bg)\n");
+ prepare_to_wait (ecs);
+ return 1;
+ }
+
+ /* Otherwise, if we were running a synchronous execution command, we
+ may need to cancel it and give the user back the terminal.
+
+ In non-stop mode, the target can't tell whether we've already
+ consumed previous stop events, so it can end up sending us a
+ no-resumed event like so:
+
+ #0 - thread 1 is left stopped
+
+ #1 - thread 2 is resumed and hits breakpoint
+ -> TARGET_WAITKIND_STOPPED
+
+ #2 - thread 3 is resumed and exits
+ this is the last resumed thread, so
+ -> TARGET_WAITKIND_NO_RESUMED
+
+ #3 - gdb processes stop for thread 2 and decides to re-resume
+ it.
+
+ #4 - gdb processes the TARGET_WAITKIND_NO_RESUMED event.
+ thread 2 is now resumed, so the event should be ignored.
+
+ IOW, if the stop for thread 2 doesn't end a foreground command,
+ then we need to ignore the following TARGET_WAITKIND_NO_RESUMED
+ event. But it could be that the event meant that thread 2 itself
+ (or whatever other thread was the last resumed thread) exited.
+
+ To address this we refresh the thread list and check whether we
+ have resumed threads _now_. In the example above, this removes
+ thread 3 from the thread list. If thread 2 was re-resumed, we
+ ignore this event. If we find no thread resumed, then we cancel
+ the synchronous command show "no unwaited-for " to the user. */
+ update_thread_list ();
+
+ ALL_NON_EXITED_THREADS (thread)
+ {
+ if (thread->executing
+ || thread->suspend.waitstatus_pending_p)
+ {
+ /* There were no unwaited-for children left in the target at
+ some point, but there are now. Just ignore. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: TARGET_WAITKIND_NO_RESUMED "
+ "(ignoring: found resumed)\n");
+ prepare_to_wait (ecs);
+ return 1;
+ }
+ }
+
+ /* Note however that we may find no resumed thread because the whole
+ process exited meanwhile (thus updating the thread list results
+ in an empty thread list). In this case we know we'll be getting
+ a process exit event shortly. */
+ ALL_INFERIORS (inf)
+ {
+ if (inf->pid == 0)
+ continue;
+
+ thread = any_live_thread_of_process (inf->pid);
+ if (thread == NULL)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: TARGET_WAITKIND_NO_RESUMED "
+ "(expect process exit)\n");
+ prepare_to_wait (ecs);
+ return 1;
+ }
+ }
+
+ /* Go ahead and report the event. */
+ return 0;
+}
+
/* Given an execution control state that has been freshly filled in by
an event from the inferior, figure out what it means and take
appropriate action.
return;
}
- if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED
- && target_can_async_p () && !sync_execution)
+ if (ecs->ws.kind == TARGET_WAITKIND_THREAD_EXITED)
{
- /* There were no unwaited-for children left in the target, but,
- we're not synchronously waiting for events either. Just
- ignore. Otherwise, if we were running a synchronous
- execution command, we need to cancel it and give the user
- back the terminal. */
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: TARGET_WAITKIND_NO_RESUMED (ignoring)\n");
+ fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_EXITED\n");
prepare_to_wait (ecs);
return;
}
+ if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED
+ && handle_no_resumed (ecs))
+ return;
+
/* Cache the last pid/waitstatus. */
set_last_target_status (ecs->ptid, ecs->ws);
prepare_to_wait (ecs);
return;
+ case TARGET_WAITKIND_THREAD_CREATED:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_CREATED\n");
+ if (!ptid_equal (ecs->ptid, inferior_ptid))
+ context_switch (ecs->ptid);
+ if (!switch_back_to_stepped_thread (ecs))
+ keep_going (ecs);
+ return;
+
case TARGET_WAITKIND_EXITED:
case TARGET_WAITKIND_SIGNALLED:
if (debug_infrun)
context_switch (ecs->ptid);
if (deprecated_context_hook)
- deprecated_context_hook (pid_to_thread_id (ecs->ptid));
+ deprecated_context_hook (ptid_to_global_thread_id (ecs->ptid));
}
/* At this point, get hold of the now-current thread's frame. */
/* set_momentary_breakpoint_at_pc invalidates FRAME. */
frame = NULL;
- bp->thread = tp->num;
+ bp->thread = tp->global_num;
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
}
bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
handler, bp_exception_resume);
- bp->thread = tp->num;
+ bp->thread = tp->global_num;
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
void
print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
{
+ struct thread_info *thr = inferior_thread ();
+
annotate_signal ();
- if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
+ if (ui_out_is_mi_like_p (uiout))
+ ;
+ else if (show_thread_that_caused_stop ())
{
- struct thread_info *t = inferior_thread ();
+ const char *name;
+
+ ui_out_text (uiout, "\nThread ");
+ ui_out_field_fmt (uiout, "thread-id", "%s", print_thread_id (thr));
- ui_out_text (uiout, "\n[");
- ui_out_field_string (uiout, "thread-name",
- target_pid_to_str (t->ptid));
- ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num);
- ui_out_text (uiout, " stopped");
+ name = thr->name != NULL ? thr->name : target_thread_name (thr);
+ if (name != NULL)
+ {
+ ui_out_text (uiout, " \"");
+ ui_out_field_fmt (uiout, "name", "%s", name);
+ ui_out_text (uiout, "\"");
+ }
}
+ else
+ ui_out_text (uiout, "\nProgram");
+
+ if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
+ ui_out_text (uiout, " stopped");
else
{
- ui_out_text (uiout, "\nProgram received signal ");
+ ui_out_text (uiout, " received signal ");
annotate_signal_name ();
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
"to change these tables.\n"));
}
-/* Check if it makes sense to read $_siginfo from the current thread
- at this point. If not, throw an error. */
-
-static void
-validate_siginfo_access (void)
-{
- /* No current inferior, no siginfo. */
- if (ptid_equal (inferior_ptid, null_ptid))
- error (_("No thread selected."));
-
- /* Don't try to read from a dead thread. */
- if (is_exited (inferior_ptid))
- error (_("The current thread has terminated"));
-
- /* ... or from a spinning thread. */
- if (is_running (inferior_ptid))
- error (_("Selected thread is running."));
-}
-
/* The $_siginfo convenience variable is a bit special. We don't know
for sure the type of the value until we actually have a chance to
fetch the data. The type can change depending on gdbarch, so it is
{
LONGEST transferred;
- validate_siginfo_access ();
+ /* If we can access registers, so can we access $_siginfo. Likewise
+ vice versa. */
+ validate_registers_access ();
transferred =
target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO,
{
LONGEST transferred;
- validate_siginfo_access ();
+ /* If we can access registers, so can we access $_siginfo. Likewise
+ vice versa. */
+ validate_registers_access ();
transferred = target_write (¤t_target,
TARGET_OBJECT_SIGNAL_INFO,