Non-stop linux native.

* linux-nat.c (linux_test_for_tracefork): Block events while we're
	here.
	(get_pending_status): Implement non-stop mode.
	(linux_nat_detach): Stop threads before detaching.
	(linux_nat_resume): In non-stop mode, always resume only a single
	PTID.
	(linux_handle_extended_wait): On a clone event, in non-stop mode,
	add new lwp to GDB's thread table, and mark as running, executing
	and stopped appropriately.
	(linux_nat_filter_event): Don't assume there are other running
	threads when a thread exits.
	(linux_nat_wait): Mark the main thread as running and executing.
	In non-stop mode, don't stop all lwps.
	(linux_nat_kill): Stop lwps before killing them.
	(linux_nat_thread_alive): Use signal 0 to detect if a thread is
	alive.
	(send_sigint_callback): New.
	(linux_nat_stop): New.
	(linux_nat_add_target): Set to_stop to linux_nat_stop.

	* linux-nat.h (thread_db_attach_lwp): Declare.

	* linux-thread-db.c (thread_get_info_callback): Check for new
	threads if we have none.
	(thread_from_lwp, enable_thread_event): Set proc_handle.pid to the
	stopped lwp.  Check for new threads if we have none.
	(thread_db_attach_lwp): New.
	(thread_db_init): Set proc_handle.pid to inferior_ptid.
	(check_event): Set proc_handle.pid to the stopped lwp.
	(thread_db_find_new_threads): Set proc_handle.pid to any stopped
	lwp available, bail out if there is none.

	* linux-fork.c (linux_fork_killall): Use SIGKILL instead of
	PTRACE_KILL.
This commit is contained in:
Pedro Alves 2008-07-10 22:58:37 +00:00
parent 981505ef9a
commit 4c28f408df
5 changed files with 320 additions and 46 deletions

View file

@ -1,3 +1,42 @@
2008-07-10 Pedro Alves <pedro@codesourcery.com>
Non-stop linux native.
* linux-nat.c (linux_test_for_tracefork): Block events while we're
here.
(get_pending_status): Implement non-stop mode.
(linux_nat_detach): Stop threads before detaching.
(linux_nat_resume): In non-stop mode, always resume only a single
PTID.
(linux_handle_extended_wait): On a clone event, in non-stop mode,
add new lwp to GDB's thread table, and mark as running, executing
and stopped appropriately.
(linux_nat_filter_event): Don't assume there are other running
threads when a thread exits.
(linux_nat_wait): Mark the main thread as running and executing.
In non-stop mode, don't stop all lwps.
(linux_nat_kill): Stop lwps before killing them.
(linux_nat_thread_alive): Use signal 0 to detect if a thread is
alive.
(send_sigint_callback): New.
(linux_nat_stop): New.
(linux_nat_add_target): Set to_stop to linux_nat_stop.
* linux-nat.h (thread_db_attach_lwp): Declare.
* linux-thread-db.c (thread_get_info_callback): Check for new
threads if we have none.
(thread_from_lwp, enable_thread_event): Set proc_handle.pid to the
stopped lwp. Check for new threads if we have none.
(thread_db_attach_lwp): New.
(thread_db_init): Set proc_handle.pid to inferior_ptid.
(check_event): Set proc_handle.pid to the stopped lwp.
(thread_db_find_new_threads): Set proc_handle.pid to any stopped
lwp available, bail out if there is none.
* linux-fork.c (linux_fork_killall): Use SIGKILL instead of
PTRACE_KILL.
2008-07-10 Kevin Buettner <kevinb@redhat.com>
* rs6000-tdep.c (ppc_displaced_step_fixup): Change type of

View file

@ -337,7 +337,9 @@ linux_fork_killall (void)
{
pid = PIDGET (fp->ptid);
do {
ptrace (PT_KILL, pid, 0, 0);
/* Use SIGKILL instead of PTRACE_KILL because the former works even
if the thread is running, while the later doesn't. */
kill (pid, SIGKILL);
ret = waitpid (pid, &status, 0);
/* We might get a SIGCHLD instead of an exit status. This is
aggravated by the first kill above - a child has just

View file

@ -319,6 +319,9 @@ static void linux_nat_async (void (*callback)
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
@ -521,6 +524,9 @@ linux_test_for_tracefork (int original_pid)
{
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;
@ -551,6 +557,7 @@ linux_test_for_tracefork (int original_pid)
if (ret != 0)
{
warning (_("linux_test_for_tracefork: failed to kill child"));
linux_nat_async_events (async_events_original_state);
return;
}
@ -561,6 +568,7 @@ linux_test_for_tracefork (int original_pid)
warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
"killed child"), status);
linux_nat_async_events (async_events_original_state);
return;
}
@ -600,6 +608,8 @@ linux_test_for_tracefork (int original_pid)
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.
@ -1441,16 +1451,80 @@ get_pending_status (struct lwp_info *lp, int *status)
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;
}
@ -1514,6 +1588,13 @@ linux_nat_detach (char *args, int from_tty)
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. */
@ -1603,10 +1684,17 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
/* 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. */
@ -1616,6 +1704,7 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
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. */
@ -1766,9 +1855,12 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
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)
{
@ -1785,13 +1877,38 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
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);
}
@ -2528,13 +2645,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
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
@ -2664,6 +2775,8 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
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);
@ -2891,19 +3004,23 @@ retry:
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);
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);
/* ... 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 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
@ -3035,6 +3152,13 @@ linux_nat_kill (void)
}
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);
@ -3087,22 +3211,22 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
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;
@ -4304,6 +4428,35 @@ linux_nat_set_async_mode (int on)
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)
{
@ -4334,6 +4487,9 @@ 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

View file

@ -94,6 +94,8 @@ void check_for_thread_db (void);
/* Tell the thread_db layer what native target operations to use. */
void thread_db_init (struct target_ops *);
int thread_db_attach_lwp (ptid_t ptid);
/* Find process PID's pending signal set from /proc/pid/status. */
void linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored);

View file

@ -283,7 +283,10 @@ thread_get_info_callback (const td_thrhandle_t *thp, void *infop)
if (thread_info == NULL)
{
/* New thread. Attach to it now (why wait?). */
attach_thread (thread_ptid, thp, &ti);
if (!have_threads ())
thread_db_find_new_threads ();
else
attach_thread (thread_ptid, thp, &ti);
thread_info = find_thread_pid (thread_ptid);
gdb_assert (thread_info != NULL);
}
@ -308,6 +311,8 @@ thread_from_lwp (ptid_t ptid)
LWP. */
gdb_assert (GET_LWP (ptid) != 0);
/* Access an lwp we know is stopped. */
proc_handle.pid = GET_LWP (ptid);
err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
if (err != TD_OK)
error (_("Cannot find user-level thread for LWP %ld: %s"),
@ -332,6 +337,48 @@ thread_from_lwp (ptid_t ptid)
}
/* Attach to lwp PTID, doing whatever else is required to have this
LWP under the debugger's control --- e.g., enabling event
reporting. Returns true on success. */
int
thread_db_attach_lwp (ptid_t ptid)
{
td_thrhandle_t th;
td_thrinfo_t ti;
td_err_e err;
if (!using_thread_db)
return 0;
/* This ptid comes from linux-nat.c, which should always fill in the
LWP. */
gdb_assert (GET_LWP (ptid) != 0);
/* Access an lwp we know is stopped. */
proc_handle.pid = GET_LWP (ptid);
/* If we have only looked at the first thread before libpthread was
initialized, we may not know its thread ID yet. Make sure we do
before we add another thread to the list. */
if (!have_threads ())
thread_db_find_new_threads ();
err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
if (err != TD_OK)
/* Cannot find user-level thread. */
return 0;
err = td_thr_get_info_p (&th, &ti);
if (err != TD_OK)
{
warning (_("Cannot get thread info: %s"), thread_db_err_str (err));
return 0;
}
attach_thread (ptid, &th, &ti);
return 1;
}
void
thread_db_init (struct target_ops *target)
{
@ -418,6 +465,9 @@ enable_thread_event (td_thragent_t *thread_agent, int event, CORE_ADDR *bp)
td_notify_t notify;
td_err_e err;
/* Access an lwp we know is stopped. */
proc_handle.pid = GET_LWP (inferior_ptid);
/* Get the breakpoint address for thread EVENT. */
err = td_ta_event_addr_p (thread_agent, event, &notify);
if (err != TD_OK)
@ -761,6 +811,15 @@ check_event (ptid_t ptid)
if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
return;
/* Access an lwp we know is stopped. */
proc_handle.pid = GET_LWP (ptid);
/* If we have only looked at the first thread before libpthread was
initialized, we may not know its thread ID yet. Make sure we do
before we add another thread to the list. */
if (!have_threads ())
thread_db_find_new_threads ();
/* If we are at a create breakpoint, we do not know what new lwp
was created and cannot specifically locate the event message for it.
We have to call td_ta_event_getmsg() to get
@ -951,11 +1010,27 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
return 0;
}
/* Search for new threads, accessing memory through stopped thread
PTID. */
static void
thread_db_find_new_threads (void)
{
td_err_e err;
struct lwp_info *lp;
ptid_t ptid;
/* In linux, we can only read memory through a stopped lwp. */
ALL_LWPS (lp, ptid)
if (lp->stopped)
break;
if (!lp)
/* There is no stopped thread. Bail out. */
return;
/* Access an lwp we know is stopped. */
proc_handle.pid = GET_LWP (ptid);
/* Iterate over all user-space threads to discover new threads. */
err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL,
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,