static int linux_nat_async_mask (int mask);
static int kill_lwp (int lwpid, int signo);
+static int send_sigint_callback (struct lwp_info *lp, void *data);
+static int stop_callback (struct lwp_info *lp, void *data);
+
/* Captures the result of a successful waitpid call, along with the
options used in that call. */
struct waitpid_result
{
int child_pid, ret, status;
long second_pid;
+ enum sigchld_state async_events_original_state;
+
+ async_events_original_state = linux_nat_async_events (sigchld_sync);
linux_supports_tracefork_flag = 0;
linux_supports_tracevforkdone_flag = 0;
if (ret != 0)
{
warning (_("linux_test_for_tracefork: failed to kill child"));
+ linux_nat_async_events (async_events_original_state);
return;
}
warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
"killed child"), status);
+ linux_nat_async_events (async_events_original_state);
return;
}
if (ret != 0)
warning (_("linux_test_for_tracefork: failed to kill child"));
my_waitpid (child_pid, &status, 0);
+
+ linux_nat_async_events (async_events_original_state);
}
/* Return non-zero iff we have tracefork functionality available.
{
struct lwp_info *lp;
- init_thread_list ();
init_lwp_list ();
lp = add_lwp (new_ptid);
- add_thread_silent (new_ptid);
lp->stopped = 1;
-}
-
-/* Record a PTID for later deletion. */
-
-struct saved_ptids
-{
- ptid_t ptid;
- struct saved_ptids *next;
-};
-static struct saved_ptids *threads_to_delete;
-
-static void
-record_dead_thread (ptid_t ptid)
-{
- struct saved_ptids *p = xmalloc (sizeof (struct saved_ptids));
- p->ptid = ptid;
- p->next = threads_to_delete;
- threads_to_delete = p;
-}
-
-/* Delete any dead threads which are not the current thread. */
-
-static void
-prune_lwps (void)
-{
- struct saved_ptids **p = &threads_to_delete;
- while (*p)
- if (! ptid_equal ((*p)->ptid, inferior_ptid))
- {
- struct saved_ptids *tmp = *p;
- delete_thread (tmp->ptid);
- *p = tmp->next;
- xfree (tmp);
- }
- else
- p = &(*p)->next;
+ init_thread_list ();
+ add_thread_silent (new_ptid);
}
/* Handle the exit of a single thread LP. */
if (print_thread_events)
printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (lp->ptid));
- /* Core GDB cannot deal with us deleting the current thread. */
- if (!ptid_equal (lp->ptid, inferior_ptid))
- delete_thread (lp->ptid);
- else
- record_dead_thread (lp->ptid);
+ delete_thread (lp->ptid);
}
delete_lwp (lp->ptid);
events are always cached in waitpid_queue. */
*status = 0;
- if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
+
+ if (non_stop)
{
- if (stop_signal != TARGET_SIGNAL_0
- && signal_pass_state (stop_signal))
- *status = W_STOPCODE (target_signal_to_host (stop_signal));
+ enum target_signal signo = TARGET_SIGNAL_0;
+
+ if (is_executing (lp->ptid))
+ {
+ /* If the core thought this lwp was executing --- e.g., the
+ executing property hasn't been updated yet, but the
+ thread has been stopped with a stop_callback /
+ stop_wait_callback sequence (see linux_nat_detach for
+ example) --- we can only have pending events in the local
+ queue. */
+ if (queued_waitpid (GET_LWP (lp->ptid), status, __WALL) != -1)
+ {
+ if (WIFSTOPPED (status))
+ signo = target_signal_from_host (WSTOPSIG (status));
+
+ /* If not stopped, then the lwp is gone, no use in
+ resending a signal. */
+ }
+ }
+ else
+ {
+ /* If the core knows the thread is not executing, then we
+ have the last signal recorded in
+ thread_info->stop_signal, unless this is inferior_ptid,
+ in which case, it's in the global stop_signal, due to
+ context switching. */
+
+ if (ptid_equal (lp->ptid, inferior_ptid))
+ signo = stop_signal;
+ else
+ {
+ struct thread_info *tp = find_thread_pid (lp->ptid);
+ gdb_assert (tp);
+ signo = tp->stop_signal;
+ }
+ }
+
+ if (signo != TARGET_SIGNAL_0
+ && !signal_pass_state (signo))
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog, "\
+GPT: lwp %s had signal %s, but it is in no pass state\n",
+ target_pid_to_str (lp->ptid),
+ target_signal_to_string (signo));
+ }
+ else
+ {
+ if (signo != TARGET_SIGNAL_0)
+ *status = W_STOPCODE (target_signal_to_host (signo));
+
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "GPT: lwp %s as pending signal %s\n",
+ target_pid_to_str (lp->ptid),
+ target_signal_to_string (signo));
+ }
}
- else if (target_can_async_p ())
- queued_waitpid (GET_LWP (lp->ptid), status, __WALL);
else
- *status = lp->status;
+ {
+ if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
+ {
+ if (stop_signal != TARGET_SIGNAL_0
+ && signal_pass_state (stop_signal))
+ *status = W_STOPCODE (target_signal_to_host (stop_signal));
+ }
+ else if (target_can_async_p ())
+ queued_waitpid (GET_LWP (lp->ptid), status, __WALL);
+ else
+ *status = lp->status;
+ }
return 0;
}
if (target_can_async_p ())
linux_nat_async (NULL, 0);
+ /* Stop all threads before detaching. ptrace requires that the
+ thread is stopped to sucessfully detach. */
+ iterate_over_lwps (stop_callback, NULL);
+ /* ... and wait until all of them have reported back that
+ they're no longer running. */
+ iterate_over_lwps (stop_wait_callback, NULL);
+
iterate_over_lwps (detach_callback, NULL);
/* Only the initial process should be left right now. */
signo ? strsignal (signo) : "0",
target_pid_to_str (inferior_ptid));
- prune_lwps ();
-
if (target_can_async_p ())
/* Block events while we're here. */
linux_nat_async_events (sigchld_sync);
/* A specific PTID means `step only this process id'. */
resume_all = (PIDGET (ptid) == -1);
- if (resume_all)
- iterate_over_lwps (resume_set_callback, NULL);
- else
- iterate_over_lwps (resume_clear_callback, NULL);
+ if (non_stop && resume_all)
+ internal_error (__FILE__, __LINE__,
+ "can't resume all in non-stop mode");
+
+ if (!non_stop)
+ {
+ if (resume_all)
+ iterate_over_lwps (resume_set_callback, NULL);
+ else
+ iterate_over_lwps (resume_clear_callback, NULL);
+ }
/* If PID is -1, it's the current inferior that should be
handled specially. */
lp = find_lwp_pid (ptid);
gdb_assert (lp != NULL);
+ /* Convert to something the lower layer understands. */
ptid = pid_to_ptid (GET_LWP (lp->ptid));
/* Remember if we're stepping. */
ourstatus->kind = TARGET_WAITKIND_VFORKED;
else
{
+ struct cleanup *old_chain;
+
ourstatus->kind = TARGET_WAITKIND_IGNORE;
new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
new_lp->cloned = 1;
+ new_lp->stopped = 1;
if (WSTOPSIG (status) != SIGSTOP)
{
else
status = 0;
- if (stopping)
- new_lp->stopped = 1;
- else
+ if (non_stop)
+ {
+ /* Add the new thread to GDB's lists as soon as possible
+ so that:
+
+ 1) the frontend doesn't have to wait for a stop to
+ display them, and,
+
+ 2) we tag it with the correct running state. */
+
+ /* If the thread_db layer is active, let it know about
+ this new thread, and add it to GDB's list. */
+ if (!thread_db_attach_lwp (new_lp->ptid))
+ {
+ /* We're not using thread_db. Add it to GDB's
+ list. */
+ target_post_attach (GET_LWP (new_lp->ptid));
+ add_thread (new_lp->ptid);
+ }
+
+ if (!stopping)
+ {
+ set_running (new_lp->ptid, 1);
+ set_executing (new_lp->ptid, 1);
+ }
+ }
+
+ if (!stopping)
{
+ new_lp->stopped = 0;
new_lp->resumed = 1;
- ptrace (PTRACE_CONT,
- PIDGET (lp->waitstatus.value.related_pid), 0,
+ ptrace (PTRACE_CONT, new_pid, 0,
status ? WSTOPSIG (status) : 0);
}
not the end of the debugged application and should be
ignored. */
if (num_lwps > 0)
- {
- /* Make sure there is at least one thread running. */
- gdb_assert (iterate_over_lwps (running_callback, NULL));
-
- /* Discard the event. */
- return NULL;
- }
+ return NULL;
}
/* Check if the current LWP has previously exited. In the nptl
lp->resumed = 1;
/* Add the main thread to GDB's thread list. */
add_thread_silent (lp->ptid);
+ set_running (lp->ptid, 1);
+ set_executing (lp->ptid, 1);
}
sigemptyset (&flush_mask);
fprintf_unfiltered (gdb_stdlog, "LLW: Candidate event %s in %s.\n",
status_to_str (status), target_pid_to_str (lp->ptid));
- /* Now stop all other LWP's ... */
- iterate_over_lwps (stop_callback, NULL);
-
- /* ... and wait until all of them have reported back that they're no
- longer running. */
- iterate_over_lwps (stop_wait_callback, &flush_mask);
- iterate_over_lwps (flush_callback, &flush_mask);
-
- /* If we're not waiting for a specific LWP, choose an event LWP from
- among those that have had events. Giving equal priority to all
- LWPs that have had events helps prevent starvation. */
- if (pid == -1)
- select_event_lwp (&lp, &status);
+ if (!non_stop)
+ {
+ /* Now stop all other LWP's ... */
+ iterate_over_lwps (stop_callback, NULL);
+
+ /* ... and wait until all of them have reported back that
+ they're no longer running. */
+ iterate_over_lwps (stop_wait_callback, &flush_mask);
+ iterate_over_lwps (flush_callback, &flush_mask);
+
+ /* If we're not waiting for a specific LWP, choose an event LWP
+ from among those that have had events. Giving equal priority
+ to all LWPs that have had events helps prevent
+ starvation. */
+ if (pid == -1)
+ select_event_lwp (&lp, &status);
+ }
/* Now that we've selected our final event LWP, cancel any
breakpoints in other LWPs that have hit a GDB breakpoint. See
}
else
{
+ /* Stop all threads before killing them, since ptrace requires
+ that the thread is stopped to sucessfully PTRACE_KILL. */
+ iterate_over_lwps (stop_callback, NULL);
+ /* ... and wait until all of them have reported back that
+ they're no longer running. */
+ iterate_over_lwps (stop_wait_callback, NULL);
+
/* Kill all LWP's ... */
iterate_over_lwps (kill_callback, NULL);
static int
linux_nat_thread_alive (ptid_t ptid)
{
+ int err;
+
gdb_assert (is_lwp (ptid));
- errno = 0;
- ptrace (PTRACE_PEEKUSER, GET_LWP (ptid), 0, 0);
+ /* Send signal 0 instead of anything ptrace, because ptracing a
+ running thread errors out claiming that the thread doesn't
+ exist. */
+ err = kill_lwp (GET_LWP (ptid), 0);
+
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "LLTA: PTRACE_PEEKUSER %s, 0, 0 (%s)\n",
+ "LLTA: KILL(SIG0) %s (%s)\n",
target_pid_to_str (ptid),
- errno ? safe_strerror (errno) : "OK");
+ err ? safe_strerror (err) : "OK");
- /* Not every Linux kernel implements PTRACE_PEEKUSER. But we can
- handle that case gracefully since ptrace will first do a lookup
- for the process based upon the passed-in pid. If that fails we
- will get either -ESRCH or -EPERM, otherwise the child exists and
- is alive. */
- if (errno == ESRCH || errno == EPERM)
+ if (err != 0)
return 0;
return 1;
linux_nat_async_enabled = on;
}
+static int
+send_sigint_callback (struct lwp_info *lp, void *data)
+{
+ /* Use is_running instead of !lp->stopped, because the lwp may be
+ stopped due to an internal event, and we want to interrupt it in
+ that case too. What we want is to check if the thread is stopped
+ from the point of view of the user. */
+ if (is_running (lp->ptid))
+ kill_lwp (GET_LWP (lp->ptid), SIGINT);
+ return 0;
+}
+
+static void
+linux_nat_stop (ptid_t ptid)
+{
+ if (non_stop)
+ {
+ if (ptid_equal (ptid, minus_one_ptid))
+ iterate_over_lwps (send_sigint_callback, &ptid);
+ else
+ {
+ struct lwp_info *lp = find_lwp_pid (ptid);
+ send_sigint_callback (lp, NULL);
+ }
+ }
+ else
+ linux_ops->to_stop (ptid);
+}
+
void
linux_nat_add_target (struct target_ops *t)
{
t->to_terminal_inferior = linux_nat_terminal_inferior;
t->to_terminal_ours = linux_nat_terminal_ours;
+ /* Methods for non-stop support. */
+ t->to_stop = linux_nat_stop;
+
/* We don't change the stratum; this target will sit at
process_stratum and thread_db will set at thread_stratum. This
is a little strange, since this is a multi-threaded-capable