From 84636d2874122cf547b3eaee494544636931c083 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 2 Sep 2011 21:03:06 +0000 Subject: [PATCH] 2011-09-02 Pedro Alves * linux-nat.c (in_pid_list_p): New. (linux_record_stopped_pid): Delete. (lin_lwp_attach_lwp): Check if PTRACE_ATTACH failed because we're already attached to the LWP. Return an indication if so. (linux_nat_filter_event): Adjust. * linux-thread-db.c (attach_thread): Handle lin_lwp_attach_lwp returning an indication to ignore this thread. --- gdb/ChangeLog | 10 +++++++ gdb/linux-nat.c | 68 ++++++++++++++++++++++++++++++++++++------- gdb/linux-thread-db.c | 22 ++++++++++++-- 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1f278cbd8a..851ab88228 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2011-09-02 Pedro Alves + + * linux-nat.c (in_pid_list_p): New. + (linux_record_stopped_pid): Delete. + (lin_lwp_attach_lwp): Check if PTRACE_ATTACH failed because we're + already attached to the LWP. Return an indication if so. + (linux_nat_filter_event): Adjust. + * linux-thread-db.c (attach_thread): Handle lin_lwp_attach_lwp + returning an indication to ignore this thread. + 2011-09-02 Pedro Alves * top.c: Include interps.h. diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 45daea7b8e..30d6857056 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -330,6 +330,17 @@ add_to_pid_list (struct simple_pid_list **listp, int pid, int status) *listp = new_pid; } +static int +in_pid_list_p (struct simple_pid_list *list, int pid) +{ + struct simple_pid_list *p; + + for (p = list; p != NULL; p = p->next) + if (p->pid == pid) + return 1; + return 0; +} + static int pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp) { @@ -348,12 +359,6 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp) return 0; } -static void -linux_record_stopped_pid (int pid, int status) -{ - add_to_pid_list (&stopped_pids, pid, status); -} - /* A helper function for linux_test_for_tracefork, called after fork (). */ @@ -1386,20 +1391,25 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned, return status; } -/* Attach to the LWP specified by PID. Return 0 if successful or -1 - if the new LWP could not be attached. */ +/* Attach to the LWP specified by PID. Return 0 if successful, -1 if + the new LWP could not be attached, or 1 if we're already auto + attached to this thread, but haven't processed the + PTRACE_EVENT_CLONE event of its parent thread, so we just ignore + its existance, without considering it an error. */ int lin_lwp_attach_lwp (ptid_t ptid) { struct lwp_info *lp; sigset_t prev_mask; + int lwpid; gdb_assert (is_lwp (ptid)); block_child_signals (&prev_mask); lp = find_lwp_pid (ptid); + lwpid = GET_LWP (ptid); /* We assume that we're already attached to any LWP that has an id equal to the overall process id, and to any LWP that is already @@ -1407,12 +1417,48 @@ lin_lwp_attach_lwp (ptid_t ptid) and we've had PID wraparound since we last tried to stop all threads, this assumption might be wrong; fortunately, this is very unlikely to happen. */ - if (GET_LWP (ptid) != GET_PID (ptid) && lp == NULL) + if (lwpid != GET_PID (ptid) && lp == NULL) { int status, cloned = 0, signalled = 0; - if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) + if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0) { + if (linux_supports_tracefork_flag) + { + /* If we haven't stopped all threads when we get here, + we may have seen a thread listed in thread_db's list, + but not processed the PTRACE_EVENT_CLONE yet. If + that's the case, ignore this new thread, and let + normal event handling discover it later. */ + if (in_pid_list_p (stopped_pids, lwpid)) + { + /* We've already seen this thread stop, but we + haven't seen the PTRACE_EVENT_CLONE extended + event yet. */ + restore_child_signals_mask (&prev_mask); + return 0; + } + else + { + int new_pid; + int status; + + /* See if we've got a stop for this new child + pending. If so, we're already attached. */ + new_pid = my_waitpid (lwpid, &status, WNOHANG); + if (new_pid == -1 && errno == ECHILD) + new_pid = my_waitpid (lwpid, &status, __WCLONE | WNOHANG); + if (new_pid != -1) + { + if (WIFSTOPPED (status)) + add_to_pid_list (&stopped_pids, lwpid, status); + + restore_child_signals_mask (&prev_mask); + return 1; + } + } + } + /* If we fail to attach to the thread, issue a warning, but continue. One way this can happen is if thread creation is interrupted; as of Linux kernel 2.6.19, a @@ -3084,7 +3130,7 @@ linux_nat_filter_event (int lwpid, int status, int options) from waitpid before or after the event is. */ if (WIFSTOPPED (status) && !lp) { - linux_record_stopped_pid (lwpid, status); + add_to_pid_list (&stopped_pids, lwpid, status); return NULL; } diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index dda2bff7a1..8141b203b2 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -1140,9 +1140,25 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, /* Under GNU/Linux, we have to attach to each and every thread. */ if (target_has_execution - && tp == NULL - && lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))) < 0) - return 0; + && tp == NULL) + { + int res; + + res = lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))); + if (res < 0) + { + /* Error, stop iterating. */ + return 0; + } + else if (res > 0) + { + /* Pretend this thread doesn't exist yet, and keep + iterating. */ + return 1; + } + + /* Otherwise, we sucessfully attached to the thread. */ + } /* Construct the thread's private data. */ private = xmalloc (sizeof (struct private_thread_info));