summaryrefslogtreecommitdiff
path: root/gdb/linux-nat.c
diff options
context:
space:
mode:
authorPedro Alves <pedro@codesourcery.com>2009-05-18 14:07:15 +0000
committerPedro Alves <pedro@codesourcery.com>2009-05-18 14:07:15 +0000
commit3c35d8466c33badf768ae27dd3f2dffa280ac3cd (patch)
treedbfc9f75d0c85eeed622e26592d823c8b114135e /gdb/linux-nat.c
parent072b48a4923b53a5a06ab933b856fae18f537cfd (diff)
downloadgdb-3c35d8466c33badf768ae27dd3f2dffa280ac3cd.tar.gz
* fork-child.c (fork_inferior): Only reset the thread list if this
is the first inferior. (startup_inferior): If the target support multi-process, tell it to resume only the new process. * linux-nat.c (num_lwps): Delete global. (purge_lwp_list): New function. (num_lwps): New function. (add_lwp, delete_lwp): Adjust. (ptid_match): New. (iterate_over_lwps): Add filter argument. Handle it. (linux_nat_attach): Remove FIXME note. (linux_nat_detach): Adjust to iterate over threads of the inferior we're detaching from. Adjust to num_lwps being a function. Don't assume the head of the lwp list is the main thread of the process we're detaching from. Don't destroy the LWP list. (resume_callback): Add debug output. (linux_nat_resume): Handle resuming a single inferior. Allow a wildcard resume in non-stop mode. (linux_handle_extended_wait): Don't assume inferior_ptid is the correct inferior of the parent LWP. (status_callback): Also check lp->waitstatus. (select_event_lwp): Add new filter parameter. Handle it. (linux_nat_filter_event): Adjust to num_lwps being a function. (linux_nat_wait_1): When adding the first lwp of the inferior, use an is_lwp check instead of checking for the number of lwps. (linux_nat_wait_1): Handle waiting for a specific tgid. Handle pending process exit statuses. (linux_nat_mourn_inferior): Don't destroy all the LWP info. Instead delete LWPs of the inferior that we're mourning. Don't unregister from the event loop here. (linux_nat_pid_to_str): Use `num_lwps'. (linux_nat_make_corefile_notes): Adjust to walk over lwps of a single inferior. (linux_nat_is_async_p): Check if async was masked out. (linux_multi_process): New global. (linux_nat_supports_multi_process): New. (linux_nat_stop_lwp): Remove LWP filtering. It is done by the caller. (linux_nat_stop): Adjust to make iterate_over_lwps itself do the LWP filtering. (linux_nat_close): New. (linux_nat_add_target): Register linux_nat_close and linux_nat_supports_multi_process. * linux-nat.h (iterate_over_lwps): Add filter argument. * linux-thread-db.c (thread_db_handle): Delete. (proc_handle, thread_agent, td_init_p, td_ta_new_p) (td_ta_map_id2thr_p, td_ta_map_lwp2thr_p, td_ta_thr_iter_p) (td_ta_event_addr_p, td_ta_set_event_p, td_ta_event_getmsg_p) (td_thr_validate_p, td_thr_get_info_p, td_thr_event_enable_p) (td_thr_tls_get_addr_p, td_create_bp_addr, td_death_bp_addr): No longer globals, moved to... (struct thread_db_info): ... this new structure. (thread_db_list): New. (add_thread_db_info, get_thread_db_info, delete_thread_db_info): New. (have_threads_callback): Filter out threads of all inferiors but the one specified by the ARGS argument. (have_threads): Add ptid argument specifying the inferior we're interested in. Handle it. (struct thread_get_info_inout): New. (thread_get_info_callback, thread_from_lwp): Adjust to use it. (thread_db_attach_lwp): Check that inferior of the passed in thread is using thread-db. Adjust. (enable_thread_event): Remove thread_agent parameter. Instead, get it from the per-inferior thread-db info. (dladdr_to_soname): Move higher up. (enable_thread_event_reporting): Adjust to use per-inferior thread-db info. (try_thread_db_load_1): Replace `handle' parameter by a thread_db_info parameter. Adjust to use per-inferior thread-db info. (try_thread_db_load): Adjust to use per-inferior thread-db info. (thread_db_load, disable_thread_event_reporting): Ditto. (check_for_thread_db): Remove conditional reporting of which libthread_db is in use. (thread_db_new_objfile): Add comment about inferior_ptid. (attach_thread): Adjust to use per-inferior thread-db info. (thread_db_detach): Adjust to use per-inferior thread-db info. Remove thread event breakpoints of the current inferior. Only unpush the thread-db target if there are no more processes using it. (check_event): Adjust to use per-inferior thread-db info. (thread_db_wait): Adjust to use per-inferior thread-db info. Only unpush the thread-db target if there are no more processes using it. (thread_db_mourn_inferior): Adjust to use per-inferior thread-db info. Mark breakpoints of the current inferior out before deleting them. Only unpush the thread-db target if there are no more processes using it. (find_new_threads_callback): Adjust to use per-inferior thread_db info. (thread_db_find_new_threads_1): Add new ptid argument. Adjust to use per-inferior thread-db info. (thread_db_find_new_threads): Adjust to use per-inferior thread-db info. (thread_db_get_thread_local_address): Adjust. (thread_db_get_ada_task_ptid): Adjust. * inf-ptrace.c (inf_ptrace_mourn_inferior): Only unpush the target if there no more processes left to debug. * thread.c (set_running, set_executing): Handle resuming all threads of a single inferior. * mi/mi-interp.c (mi_output_running_pid): New. (mi_inferior_count): New. (mi_on_resume): For backwards compatibility, if resuming all threads of an inferior, and there is only one inferior, output "all".
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r--gdb/linux-nat.c453
1 files changed, 316 insertions, 137 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index beff012fab6..553d676ae52 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -841,9 +841,6 @@ linux_child_insert_exec_catchpoint (int pid)
/* List of known LWPs. */
struct lwp_info *lwp_list;
-
-/* Number of LWPs in the list. */
-static int num_lwps;
/* Original signal mask. */
@@ -926,7 +923,48 @@ init_lwp_list (void)
}
lwp_list = NULL;
- num_lwps = 0;
+}
+
+/* Remove all LWPs belong to PID from the lwp list. */
+
+static void
+purge_lwp_list (int pid)
+{
+ struct lwp_info *lp, *lpprev, *lpnext;
+
+ lpprev = NULL;
+
+ for (lp = lwp_list; lp; lp = lpnext)
+ {
+ lpnext = lp->next;
+
+ if (ptid_get_pid (lp->ptid) == pid)
+ {
+ if (lp == lwp_list)
+ lwp_list = lp->next;
+ else
+ lpprev->next = lp->next;
+
+ xfree (lp);
+ }
+ else
+ lpprev = lp;
+ }
+}
+
+/* Return the number of known LWPs in the tgid given by PID. */
+
+static int
+num_lwps (int pid)
+{
+ int count = 0;
+ struct lwp_info *lp;
+
+ for (lp = lwp_list; lp; lp = lp->next)
+ if (ptid_get_pid (lp->ptid) == pid)
+ count++;
+
+ return count;
}
/* Add the LWP specified by PID to the list. Return a pointer to the
@@ -950,9 +988,8 @@ add_lwp (ptid_t ptid)
lp->next = lwp_list;
lwp_list = lp;
- ++num_lwps;
- if (num_lwps > 1 && linux_nat_new_thread != NULL)
+ if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
linux_nat_new_thread (ptid);
return lp;
@@ -974,8 +1011,6 @@ delete_lwp (ptid_t ptid)
if (!lp)
return;
- num_lwps--;
-
if (lpprev)
lpprev->next = lp->next;
else
@@ -1005,21 +1040,54 @@ find_lwp_pid (ptid_t ptid)
return NULL;
}
+/* Returns true if PTID matches filter FILTER. FILTER can be the wild
+ card MINUS_ONE_PTID (all ptid match it); can be a ptid representing
+ a process (ptid_is_pid returns true), in which case, all lwps of
+ that give process match, lwps of other process do not; or, it can
+ represent a specific thread, in which case, only that thread will
+ match true. PTID must represent an LWP, it can never be a wild
+ card. */
+
+static int
+ptid_match (ptid_t ptid, ptid_t filter)
+{
+ /* Since both parameters have the same type, prevent easy mistakes
+ from happening. */
+ gdb_assert (!ptid_equal (ptid, minus_one_ptid)
+ && !ptid_equal (ptid, null_ptid));
+
+ if (ptid_equal (filter, minus_one_ptid))
+ return 1;
+ if (ptid_is_pid (filter)
+ && ptid_get_pid (ptid) == ptid_get_pid (filter))
+ return 1;
+ else if (ptid_equal (ptid, filter))
+ return 1;
+
+ return 0;
+}
+
/* Call CALLBACK with its second argument set to DATA for every LWP in
the list. If CALLBACK returns 1 for a particular LWP, return a
pointer to the structure describing that LWP immediately.
Otherwise return NULL. */
struct lwp_info *
-iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
+iterate_over_lwps (ptid_t filter,
+ int (*callback) (struct lwp_info *, void *),
+ void *data)
{
struct lwp_info *lp, *lpnext;
for (lp = lwp_list; lp; lp = lpnext)
{
lpnext = lp->next;
- if ((*callback) (lp, data))
- return lp;
+
+ if (ptid_match (lp->ptid, filter))
+ {
+ if ((*callback) (lp, data))
+ return lp;
+ }
}
return NULL;
@@ -1296,8 +1364,6 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
int status;
ptid_t ptid;
- /* FIXME: We should probably accept a list of process id's, and
- attach all of them. */
linux_ops->to_attach (ops, args, from_tty);
/* The ptrace base target adds the main thread with (pid,0,0)
@@ -1457,25 +1523,30 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
int pid;
int status;
enum target_signal sig;
+ struct lwp_info *main_lwp;
+
+ pid = GET_PID (inferior_ptid);
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);
+ iterate_over_lwps (pid_to_ptid (pid), 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 (pid_to_ptid (pid), stop_wait_callback, NULL);
- iterate_over_lwps (detach_callback, NULL);
+ iterate_over_lwps (pid_to_ptid (pid), detach_callback, NULL);
/* Only the initial process should be left right now. */
- gdb_assert (num_lwps == 1);
+ gdb_assert (num_lwps (GET_PID (inferior_ptid)) == 1);
+
+ main_lwp = find_lwp_pid (pid_to_ptid (pid));
/* Pass on any pending signal for the last LWP. */
if ((args == NULL || *args == '\0')
- && get_pending_status (lwp_list, &status) != -1
+ && get_pending_status (main_lwp, &status) != -1
&& WIFSTOPPED (status))
{
/* Put the signal number in ARGS so that inf_ptrace_detach will
@@ -1485,13 +1556,10 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
fprintf_unfiltered (gdb_stdlog,
"LND: Sending signal %s to %s\n",
args,
- target_pid_to_str (lwp_list->ptid));
+ target_pid_to_str (main_lwp->ptid));
}
- /* Destroy LWP info; it's no longer valid. */
- init_lwp_list ();
-
- pid = ptid_get_pid (inferior_ptid);
+ delete_lwp (main_lwp->ptid);
if (forks_exist_p ())
{
@@ -1515,6 +1583,11 @@ resume_callback (struct lwp_info *lp, void *data)
{
if (lp->stopped && lp->status == 0)
{
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "RC: PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
+ target_pid_to_str (lp->ptid));
+
linux_ops->to_resume (linux_ops,
pid_to_ptid (GET_LWP (lp->ptid)),
0, TARGET_SIGNAL_0);
@@ -1556,7 +1629,7 @@ linux_nat_resume (struct target_ops *ops,
{
sigset_t prev_mask;
struct lwp_info *lp;
- int resume_all;
+ int resume_many;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@@ -1569,37 +1642,29 @@ linux_nat_resume (struct target_ops *ops,
block_child_signals (&prev_mask);
/* A specific PTID means `step only this process id'. */
- resume_all = (PIDGET (ptid) == -1);
-
- if (non_stop && resume_all)
- internal_error (__FILE__, __LINE__,
- "can't resume all in non-stop mode");
+ resume_many = (ptid_equal (minus_one_ptid, ptid)
+ || ptid_is_pid (ptid));
if (!non_stop)
{
- if (resume_all)
- iterate_over_lwps (resume_set_callback, NULL);
- else
- iterate_over_lwps (resume_clear_callback, NULL);
+ /* Mark the lwps we're resuming as resumed. */
+ iterate_over_lwps (minus_one_ptid, resume_clear_callback, NULL);
+ iterate_over_lwps (ptid, resume_set_callback, NULL);
}
+ else
+ iterate_over_lwps (minus_one_ptid, resume_set_callback, NULL);
- /* If PID is -1, it's the current inferior that should be
- handled specially. */
- if (PIDGET (ptid) == -1)
- ptid = inferior_ptid;
-
- lp = find_lwp_pid (ptid);
+ /* See if it's the current inferior that should be handled
+ specially. */
+ if (resume_many)
+ lp = find_lwp_pid (inferior_ptid);
+ else
+ 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. */
lp->step = step;
- /* Mark this LWP as resumed. */
- lp->resumed = 1;
-
/* If we have a pending wait status for this thread, there is no
point in resuming the process. But first make sure that
linux_nat_wait won't preemptively handle the event - we
@@ -1613,7 +1678,7 @@ linux_nat_resume (struct target_ops *ops,
int saved_signo;
struct inferior *inf;
- inf = find_inferior_pid (ptid_get_pid (ptid));
+ inf = find_inferior_pid (ptid_get_pid (lp->ptid));
gdb_assert (inf);
saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
@@ -1662,8 +1727,11 @@ linux_nat_resume (struct target_ops *ops,
resume_callback. */
lp->stopped = 0;
- if (resume_all)
- iterate_over_lwps (resume_callback, NULL);
+ if (resume_many)
+ iterate_over_lwps (ptid, resume_callback, NULL);
+
+ /* Convert to something the lower layer understands. */
+ ptid = pid_to_ptid (GET_LWP (lp->ptid));
linux_ops->to_resume (linux_ops, ptid, step, signo);
memset (&lp->siginfo, 0, sizeof (lp->siginfo));
@@ -1757,7 +1825,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
struct cleanup *old_chain;
ourstatus->kind = TARGET_WAITKIND_IGNORE;
- new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
+ new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (lp->ptid)));
new_lp->cloned = 1;
new_lp->stopped = 1;
@@ -2181,7 +2249,12 @@ status_callback (struct lwp_info *lp, void *data)
{
/* Only report a pending wait status if we pretend that this has
indeed been resumed. */
- return (lp->status != 0 && lp->resumed);
+ /* We check for lp->waitstatus in addition to lp->status, because we
+ can have pending process exits recorded in lp->waitstatus, and
+ W_EXITCODE(0,0) == 0. */
+ return ((lp->status != 0
+ || lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
+ && lp->resumed);
}
/* Return non-zero if LP isn't stopped. */
@@ -2303,7 +2376,7 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
/* Select one LWP out of those that have events pending. */
static void
-select_event_lwp (struct lwp_info **orig_lp, int *status)
+select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
{
int num_events = 0;
int random_selector;
@@ -2313,7 +2386,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
(*orig_lp)->status = *status;
/* Give preference to any LWP that is being single-stepped. */
- event_lp = iterate_over_lwps (select_singlestep_lwp_callback, NULL);
+ event_lp = iterate_over_lwps (filter,
+ select_singlestep_lwp_callback, NULL);
if (event_lp != NULL)
{
if (debug_linux_nat)
@@ -2327,7 +2401,7 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
which have had SIGTRAP events. */
/* First see how many SIGTRAP events we have. */
- iterate_over_lwps (count_events_callback, &num_events);
+ iterate_over_lwps (filter, count_events_callback, &num_events);
/* Now randomly pick a LWP out of those that have had a SIGTRAP. */
random_selector = (int)
@@ -2338,7 +2412,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
"SEL: Found %d SIGTRAP events, selecting #%d\n",
num_events, random_selector);
- event_lp = iterate_over_lwps (select_event_lwp_callback,
+ event_lp = iterate_over_lwps (filter,
+ select_event_lwp_callback,
&random_selector);
}
@@ -2456,7 +2531,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
}
/* Check if the thread has exited. */
- if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
+ if ((WIFEXITED (status) || WIFSIGNALED (status))
+ && num_lwps (GET_PID (lp->ptid)) > 1)
{
/* If this is the main thread, we must stop all threads and verify
if they are still alive. This is because in the nptl thread model
@@ -2471,7 +2547,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
{
lp->stopped = 1;
- iterate_over_lwps (stop_and_resume_callback, NULL);
+ iterate_over_lwps (pid_to_ptid (GET_PID (lp->ptid)),
+ stop_and_resume_callback, NULL);
}
if (debug_linux_nat)
@@ -2479,7 +2556,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
"LLW: %s exited.\n",
target_pid_to_str (lp->ptid));
- if (num_lwps > 1)
+ if (num_lwps (GET_PID (lp->ptid)) > 1)
{
/* If there is at least one more LWP, then the exit signal
was not the end of the debugged application and should be
@@ -2493,8 +2570,10 @@ linux_nat_filter_event (int lwpid, int status, int options)
thread model, LWPs other than the main thread do not issue
signals when they exit so we must check whenever the thread has
stopped. A similar check is made in stop_wait_callback(). */
- if (num_lwps > 1 && !linux_thread_alive (lp->ptid))
+ if (num_lwps (GET_PID (lp->ptid)) > 1 && !linux_thread_alive (lp->ptid))
{
+ ptid_t ptid = pid_to_ptid (GET_PID (lp->ptid));
+
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLW: %s exited.\n",
@@ -2503,7 +2582,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
exit_lwp (lp);
/* Make sure there is at least one thread running. */
- gdb_assert (iterate_over_lwps (running_callback, NULL));
+ gdb_assert (iterate_over_lwps (ptid, running_callback, NULL));
/* Discard the event. */
return NULL;
@@ -2583,7 +2662,7 @@ linux_nat_wait_1 (struct target_ops *ops,
struct lwp_info *lp = NULL;
int options = 0;
int status = 0;
- pid_t pid = PIDGET (ptid);
+ pid_t pid;
if (debug_linux_nat_async)
fprintf_unfiltered (gdb_stdlog, "LLW: enter\n");
@@ -2591,10 +2670,8 @@ linux_nat_wait_1 (struct target_ops *ops,
/* The first time we get here after starting a new inferior, we may
not have added it to the LWP list yet - this is the earliest
moment at which we know its PID. */
- if (num_lwps == 0)
+ if (ptid_is_pid (inferior_ptid))
{
- gdb_assert (!is_lwp (inferior_ptid));
-
/* Upgrade the main thread's ptid. */
thread_change_ptid (inferior_ptid,
BUILD_LWP (GET_PID (inferior_ptid),
@@ -2607,16 +2684,29 @@ linux_nat_wait_1 (struct target_ops *ops,
/* Make sure SIGCHLD is blocked. */
block_child_signals (&prev_mask);
+ if (ptid_equal (ptid, minus_one_ptid))
+ pid = -1;
+ else if (ptid_is_pid (ptid))
+ /* A request to wait for a specific tgid. This is not possible
+ with waitpid, so instead, we wait for any child, and leave
+ children we're not interested in right now with a pending
+ status to report later. */
+ pid = -1;
+ else
+ pid = GET_LWP (ptid);
+
retry:
+ lp = NULL;
+ status = 0;
/* Make sure there is at least one LWP that has been resumed. */
- gdb_assert (iterate_over_lwps (resumed_callback, NULL));
+ gdb_assert (iterate_over_lwps (ptid, resumed_callback, NULL));
/* First check if there is a LWP with a wait status pending. */
if (pid == -1)
{
/* Any LWP that's been resumed will do. */
- lp = iterate_over_lwps (status_callback, NULL);
+ lp = iterate_over_lwps (ptid, status_callback, NULL);
if (lp)
{
status = lp->status;
@@ -2658,9 +2748,16 @@ retry:
the layer beneath us can understand. */
options = lp->cloned ? __WCLONE : 0;
pid = GET_LWP (ptid);
+
+ /* We check for lp->waitstatus in addition to lp->status,
+ because we can have pending process exits recorded in
+ lp->status and W_EXITCODE(0,0) == 0. We should probably have
+ an additional lp->status_p flag. */
+ if (status == 0 && lp->waitstatus.kind == TARGET_WAITKIND_IGNORE)
+ lp = NULL;
}
- if (status && lp->signalled)
+ if (lp && lp->signalled)
{
/* A pending SIGSTOP may interfere with the normal stream of
events. In a typical case where interference is a problem,
@@ -2697,7 +2794,7 @@ retry:
if (target_can_async_p ())
options |= WNOHANG; /* In async mode, don't block. */
- while (status == 0)
+ while (lp == NULL)
{
pid_t lwpid;
@@ -2715,14 +2812,79 @@ retry:
}
lp = linux_nat_filter_event (lwpid, status, options);
- if (!lp)
+
+ if (lp
+ && ptid_is_pid (ptid)
+ && ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
{
- /* A discarded event. */
- status = 0;
+ if (debug_linux_nat)
+ fprintf (stderr, "LWP %ld got an event %06x, leaving pending.\n",
+ ptid_get_lwp (lp->ptid), status);
+
+ if (WIFSTOPPED (status))
+ {
+ if (WSTOPSIG (status) != SIGSTOP)
+ {
+ lp->status = status;
+
+ stop_callback (lp, NULL);
+
+ /* Resume in order to collect the sigstop. */
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+
+ stop_wait_callback (lp, NULL);
+ }
+ else
+ {
+ lp->stopped = 1;
+ lp->signalled = 0;
+ }
+ }
+ else if (WIFEXITED (status) || WIFSIGNALED (status))
+ {
+ if (debug_linux_nat)
+ fprintf (stderr, "Process %ld exited while stopping LWPs\n",
+ ptid_get_lwp (lp->ptid));
+
+ /* This was the last lwp in the process. Since
+ events are serialized to GDB core, and we can't
+ report this one right now, but GDB core and the
+ other target layers will want to be notified
+ about the exit code/signal, leave the status
+ pending for the next time we're able to report
+ it. */
+ lp->status = status;
+
+ /* Prevent trying to stop this thread again. We'll
+ never try to resume it because it has a pending
+ status. */
+ lp->stopped = 1;
+
+ /* Dead LWP's aren't expected to reported a pending
+ sigstop. */
+ lp->signalled = 0;
+
+ /* Store the pending event in the waitstatus as
+ well, because W_EXITCODE(0,0) == 0. */
+ store_waitstatus (&lp->waitstatus, status);
+ }
+
+ /* Keep looking. */
+ lp = NULL;
continue;
}
- break;
+ if (lp)
+ break;
+ else
+ {
+ if (pid == -1)
+ {
+ /* waitpid did return something. Restart over. */
+ options |= __WCLONE;
+ }
+ continue;
+ }
}
if (pid == -1)
@@ -2752,7 +2914,7 @@ retry:
}
/* We shouldn't end up here unless we want to try again. */
- gdb_assert (status == 0);
+ gdb_assert (lp == NULL);
}
if (!target_can_async_p ())
@@ -2801,7 +2963,6 @@ retry:
target_pid_to_str (lp->ptid),
signo ? strsignal (signo) : "0");
lp->stopped = 0;
- status = 0;
goto retry;
}
@@ -2817,7 +2978,8 @@ retry:
will receive it - unless they're using CLONE_THREAD to
share signals. Since we only want to report it once, we
mark it as ignored for all LWPs except this one. */
- iterate_over_lwps (set_ignore_sigint, NULL);
+ iterate_over_lwps (pid_to_ptid (ptid_get_pid (ptid)),
+ set_ignore_sigint, NULL);
lp->ignore_sigint = 0;
}
else
@@ -2835,24 +2997,24 @@ retry:
if (!non_stop)
{
/* Now stop all other LWP's ... */
- iterate_over_lwps (stop_callback, NULL);
+ iterate_over_lwps (minus_one_ptid, 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 (minus_one_ptid, stop_wait_callback, NULL);
/* 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);
+ select_event_lwp (ptid, &lp, &status);
}
/* Now that we've selected our final event LWP, cancel any
breakpoints in other LWPs that have hit a GDB breakpoint. See
the comment in cancel_breakpoints_callback to find out why. */
- iterate_over_lwps (cancel_breakpoints_callback, lp);
+ iterate_over_lwps (minus_one_ptid, cancel_breakpoints_callback, lp);
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
{
@@ -3000,18 +3162,19 @@ linux_nat_kill (struct target_ops *ops)
linux_fork_killall ();
else
{
+ ptid_t ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
/* Stop all threads before killing them, since ptrace requires
that the thread is stopped to sucessfully PTRACE_KILL. */
- iterate_over_lwps (stop_callback, NULL);
+ iterate_over_lwps (ptid, 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 (ptid, stop_wait_callback, NULL);
/* Kill all LWP's ... */
- iterate_over_lwps (kill_callback, NULL);
+ iterate_over_lwps (ptid, kill_callback, NULL);
/* ... and wait until we've flushed all events. */
- iterate_over_lwps (kill_wait_callback, NULL);
+ iterate_over_lwps (ptid, kill_wait_callback, NULL);
}
target_mourn_inferior ();
@@ -3020,17 +3183,11 @@ linux_nat_kill (struct target_ops *ops)
static void
linux_nat_mourn_inferior (struct target_ops *ops)
{
- /* Destroy LWP info; it's no longer valid. */
- init_lwp_list ();
+ purge_lwp_list (ptid_get_pid (inferior_ptid));
if (! forks_exist_p ())
- {
- /* Normal case, no other forks available. */
- linux_ops->to_mourn_inferior (ops);
-
- if (target_can_async_p ())
- linux_nat_async (NULL, 0);
- }
+ /* Normal case, no other forks available. */
+ linux_ops->to_mourn_inferior (ops);
else
/* Multi-fork case. The current inferior_ptid has exited, but
there are other viable forks to debug. Delete the exiting
@@ -3174,8 +3331,8 @@ linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
static char buf[64];
if (is_lwp (ptid)
- && ((lwp_list && lwp_list->next)
- || GET_PID (ptid) != GET_LWP (ptid)))
+ && (GET_PID (ptid) != GET_LWP (ptid)
+ || num_lwps (GET_PID (ptid)) > 1))
{
snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
return buf;
@@ -3450,6 +3607,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
char psargs[80] = { '\0' };
char *note_data = NULL;
ptid_t current_ptid = inferior_ptid;
+ ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
gdb_byte *auxv;
int auxv_len;
@@ -3483,7 +3641,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
thread_args.note_size = note_size;
thread_args.num_notes = 0;
thread_args.stop_signal = find_stop_signal ();
- iterate_over_lwps (linux_nat_corefile_thread_callback, &thread_args);
+ iterate_over_lwps (filter, linux_nat_corefile_thread_callback, &thread_args);
gdb_assert (thread_args.num_notes != 0);
note_data = thread_args.note_data;
@@ -4096,7 +4254,8 @@ linux_nat_is_async_p (void)
if (!target_async_permitted)
return 0;
- return 1;
+ /* See target.h/target_async_mask. */
+ return linux_nat_async_mask_value;
}
/* target_can_async_p implementation. */
@@ -4120,6 +4279,17 @@ linux_nat_supports_non_stop (void)
return 1;
}
+/* True if we want to support multi-process. To be removed when GDB
+ supports multi-exec. */
+
+int linux_multi_process = 0;
+
+static int
+linux_nat_supports_multi_process (void)
+{
+ return linux_multi_process;
+}
+
/* target_async_mask implementation. */
static int
@@ -4317,56 +4487,48 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
static int
linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
{
- ptid_t ptid = * (ptid_t *) data;
-
- if (ptid_equal (lwp->ptid, ptid)
- || ptid_equal (minus_one_ptid, ptid)
- || (ptid_is_pid (ptid)
- && ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid)))
+ if (!lwp->stopped)
{
- if (!lwp->stopped)
- {
- int pid, status;
- ptid_t ptid = lwp->ptid;
+ int pid, status;
+ ptid_t ptid = lwp->ptid;
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LNSL: running -> suspending %s\n",
- target_pid_to_str (lwp->ptid));
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LNSL: running -> suspending %s\n",
+ target_pid_to_str (lwp->ptid));
- stop_callback (lwp, NULL);
- stop_wait_callback (lwp, NULL);
+ stop_callback (lwp, NULL);
+ stop_wait_callback (lwp, NULL);
- /* If the lwp exits while we try to stop it, there's nothing
- else to do. */
- lwp = find_lwp_pid (ptid);
- if (lwp == NULL)
- return 0;
+ /* If the lwp exits while we try to stop it, there's nothing
+ else to do. */
+ lwp = find_lwp_pid (ptid);
+ if (lwp == NULL)
+ return 0;
- /* If we didn't collect any signal other than SIGSTOP while
- stopping the LWP, push a SIGNAL_0 event. In either case,
- the event-loop will end up calling target_wait which will
- collect these. */
- if (lwp->status == 0)
- lwp->status = W_STOPCODE (0);
- async_file_mark ();
- }
- else
- {
- /* Already known to be stopped; do nothing. */
+ /* If we didn't collect any signal other than SIGSTOP while
+ stopping the LWP, push a SIGNAL_0 event. In either case, the
+ event-loop will end up calling target_wait which will collect
+ these. */
+ if (lwp->status == 0)
+ lwp->status = W_STOPCODE (0);
+ async_file_mark ();
+ }
+ else
+ {
+ /* Already known to be stopped; do nothing. */
- if (debug_linux_nat)
- {
- if (find_thread_pid (lwp->ptid)->stop_requested)
- fprintf_unfiltered (gdb_stdlog, "\
+ if (debug_linux_nat)
+ {
+ if (find_thread_pid (lwp->ptid)->stop_requested)
+ fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/stop_requested %s\n",
- target_pid_to_str (lwp->ptid));
- else
- fprintf_unfiltered (gdb_stdlog, "\
+ target_pid_to_str (lwp->ptid));
+ else
+ fprintf_unfiltered (gdb_stdlog, "\
LNSL: already stopped/no stop_requested yet %s\n",
- target_pid_to_str (lwp->ptid));
- }
+ target_pid_to_str (lwp->ptid));
}
}
return 0;
@@ -4376,11 +4538,25 @@ static void
linux_nat_stop (ptid_t ptid)
{
if (non_stop)
- iterate_over_lwps (linux_nat_stop_lwp, &ptid);
+ iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
else
linux_ops->to_stop (ptid);
}
+static void
+linux_nat_close (int quitting)
+{
+ /* Unregister from the event loop. */
+ if (target_is_async_p ())
+ target_async (NULL, 0);
+
+ /* Reset the async_masking. */
+ linux_nat_async_mask_value = 1;
+
+ if (linux_ops->to_close)
+ linux_ops->to_close (quitting);
+}
+
void
linux_nat_add_target (struct target_ops *t)
{
@@ -4411,10 +4587,13 @@ linux_nat_add_target (struct target_ops *t)
t->to_async_mask = linux_nat_async_mask;
t->to_terminal_inferior = linux_nat_terminal_inferior;
t->to_terminal_ours = linux_nat_terminal_ours;
+ t->to_close = linux_nat_close;
/* Methods for non-stop support. */
t->to_stop = linux_nat_stop;
+ t->to_supports_multi_process = linux_nat_supports_multi_process;
+
/* 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