From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32174 invoked by alias); 25 Mar 2004 16:34:41 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 32152 invoked from network); 25 Mar 2004 16:34:37 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sources.redhat.com with SMTP; 25 Mar 2004 16:34:37 -0000 Received: from drow by nevyn.them.org with local (Exim 4.30 #1 (Debian)) id 1B6XoT-0003yd-3N; Thu, 25 Mar 2004 11:34:37 -0500 Date: Thu, 25 Mar 2004 16:34:00 -0000 From: Daniel Jacobowitz To: Jeff Johnston , gdb-patches@sources.redhat.com Subject: Re: [RFC]: fix for recycled thread ids Message-ID: <20040325163437.GA15238@nevyn.them.org> Mail-Followup-To: Jeff Johnston , gdb-patches@sources.redhat.com References: <405B3F83.4030503@redhat.com> <20040319190126.GA16950@nevyn.them.org> <405B4B8C.2060801@redhat.com> <20040319194011.GA18776@nevyn.them.org> <405B66F4.4090101@redhat.com> <20040324155130.GA27748@nevyn.them.org> <20040324165625.GA10256@nevyn.them.org> <4062041F.1010302@redhat.com> <40622BEF.8030403@redhat.com> <20040325043950.GA13188@nevyn.them.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20040325043950.GA13188@nevyn.them.org> User-Agent: Mutt/1.5.1i X-SW-Source: 2004-03/txt/msg00620.txt.bz2 On Wed, Mar 24, 2004 at 11:39:50PM -0500, Daniel Jacobowitz wrote: > Do you have any code for PTRACE_EVENT_CLONE yet, or should I put > something together in the morning to verify whether that's the problem? Here you go. Again, this patch is obviously not ready to go into GDB, but I have not been able to make it misbehave yet. I don't know if all the bits it needs work right in RHEL3, or if my testing was conclusive. The highlights: - Includes most of the previous patch - Uses PTRACE_EVENT_CLONE to attach to new threads - Moves handling of events closer to the waitpid call There are some potential races but I haven't hit any of them in practice. I suspect that with a heavy fork or vfork load (not clone) you could produce interesting failure modes. Give it a try, please. If it works I'll clean it up. -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer Index: lin-lwp.c =================================================================== RCS file: /cvs/src/src/gdb/lin-lwp.c,v retrieving revision 1.53 diff -u -p -r1.53 lin-lwp.c --- lin-lwp.c 22 Mar 2004 20:18:33 -0000 1.53 +++ lin-lwp.c 25 Mar 2004 16:31:30 -0000 @@ -183,6 +183,8 @@ add_lwp (ptid_t ptid) memset (lp, 0, sizeof (struct lwp_info)); + lp->waitstatus.kind = TARGET_WAITKIND_IGNORE; + lp->ptid = ptid; lp->next = lwp_list; @@ -278,7 +280,7 @@ lin_lwp_open (char *args, int from_tty) void lin_lwp_attach_lwp (ptid_t ptid, int verbose) { - struct lwp_info *lp; + struct lwp_info *lp, *found_lp; gdb_assert (is_lwp (ptid)); @@ -293,13 +295,13 @@ lin_lwp_attach_lwp (ptid_t ptid, int ver if (verbose) printf_filtered ("[New %s]\n", target_pid_to_str (ptid)); - lp = find_lwp_pid (ptid); + found_lp = lp = find_lwp_pid (ptid); if (lp == NULL) lp = add_lwp (ptid); /* We assume that we're already attached to any LWP that has an id equal to the overall process id. */ - if (GET_LWP (ptid) != GET_PID (ptid)) + if (GET_LWP (ptid) != GET_PID (ptid) && found_lp == NULL) { pid_t pid; int status; @@ -658,6 +660,30 @@ wait_lwp (struct lwp_info *lp) gdb_assert (WIFSTOPPED (status)); + /* Handle GNU/Linux's extended waitstatus for trace events. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + { + fprintf_unfiltered (gdb_stdlog, + "WL: Handling extended status 0x%06x\n", + status); + linux_handle_extended_wait (GET_LWP (lp->ptid), status, + &lp->waitstatus); + if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS) + { + struct lwp_info *new_lp; + new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid, + GET_PID (inferior_ptid))); + new_lp->cloned = 1; + new_lp->stopped = 1; + lp->waitstatus.kind = TARGET_WAITKIND_IGNORE; + fprintf_unfiltered (gdb_stdlog, + "WL: Got clone event from LWP %d, resuming\n", + GET_LWP (lp->ptid)); + ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); + return wait_lwp (lp); + } + } + return status; } @@ -1161,7 +1187,14 @@ child_wait (ptid_t ptid, struct target_w /* Handle GNU/Linux's extended waitstatus for trace events. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) - return linux_handle_extended_wait (pid, status, ourstatus); + { + ptid_t wait_ptid; + wait_ptid = linux_handle_extended_wait (pid, status, ourstatus); + if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS) + ptrace (PTRACE_DETACH, ourstatus->value.related_pid, + 0, 0); + return wait_ptid; + } store_waitstatus (ourstatus, status); return pid_to_ptid (pid); @@ -1371,6 +1404,31 @@ retry: } } + /* Handle GNU/Linux's extended waitstatus for trace events. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + { + fprintf_unfiltered (gdb_stdlog, + "LLW: Handling extended status 0x%06x\n", + status); + linux_handle_extended_wait (GET_LWP (lp->ptid), status, + &lp->waitstatus); + if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS) + { + struct lwp_info *new_lp; + new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid, + GET_PID (inferior_ptid))); + new_lp->cloned = 1; + new_lp->stopped = 1; + lp->waitstatus.kind = TARGET_WAITKIND_IGNORE; + fprintf_unfiltered (gdb_stdlog, + "LLW: Got clone event from LWP %d, resuming\n", + GET_LWP (lp->ptid)); + ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); + status = 0; + continue; + } + } + /* Check if the thread has exited. */ if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1) { @@ -1588,14 +1646,14 @@ retry: else trap_ptid = null_ptid; - /* Handle GNU/Linux's extended waitstatus for trace events. */ - if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE) { - linux_handle_extended_wait (GET_LWP (lp->ptid), status, ourstatus); - return trap_ptid; + *ourstatus = lp->waitstatus; + lp->waitstatus.kind = TARGET_WAITKIND_IGNORE; } + else + store_waitstatus (ourstatus, status); - store_waitstatus (ourstatus, status); return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid))); } Index: linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.c,v retrieving revision 1.5 diff -u -p -r1.5 linux-nat.c --- linux-nat.c 17 Aug 2003 20:17:02 -0000 1.5 +++ linux-nat.c 25 Mar 2004 16:31:30 -0000 @@ -224,7 +224,8 @@ linux_enable_event_reporting (ptid_t pti if (! linux_supports_tracefork ()) return; - options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC; + options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC + | PTRACE_O_TRACECLONE; if (linux_supports_tracevforkdone ()) options |= PTRACE_O_TRACEVFORKDONE; @@ -391,11 +392,8 @@ linux_handle_extended_wait (int pid, int { int event = status >> 16; - if (event == PTRACE_EVENT_CLONE) - internal_error (__FILE__, __LINE__, - "unexpected clone event"); - - if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK) + if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK + || event == PTRACE_EVENT_CLONE) { unsigned long new_pid; int ret; @@ -406,12 +404,10 @@ linux_handle_extended_wait (int pid, int if (! pull_pid_from_list (&stopped_pids, new_pid)) { /* The new child has a pending SIGSTOP. We can't affect it until it - hits the SIGSTOP, but we're already attached. - - It won't be a clone (we didn't ask for clones in the event mask) - so we can just call waitpid and wait for the SIGSTOP. */ + hits the SIGSTOP, but we're already attached. */ do { - ret = waitpid (new_pid, &status, 0); + ret = waitpid (new_pid, &status, + (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0); } while (ret == -1 && errno == EINTR); if (ret == -1) perror_with_name ("waiting for new child"); @@ -423,8 +419,13 @@ linux_handle_extended_wait (int pid, int "wait returned unexpected status 0x%x", status); } - ourstatus->kind = (event == PTRACE_EVENT_FORK) - ? TARGET_WAITKIND_FORKED : TARGET_WAITKIND_VFORKED; + if (event == PTRACE_EVENT_FORK) + ourstatus->kind = TARGET_WAITKIND_FORKED; + else if (event == PTRACE_EVENT_VFORK) + ourstatus->kind = TARGET_WAITKIND_VFORKED; + else + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + ourstatus->value.related_pid = new_pid; return inferior_ptid; } Index: linux-nat.h =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.h,v retrieving revision 1.5 diff -u -p -r1.5 linux-nat.h --- linux-nat.h 14 Sep 2003 02:04:44 -0000 1.5 +++ linux-nat.h 25 Mar 2004 16:31:30 -0000 @@ -1,5 +1,5 @@ /* Native debugging support for GNU/Linux (LWP layer). - Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "target.h" + /* Structure describing an LWP. */ struct lwp_info @@ -52,6 +54,10 @@ struct lwp_info /* Non-zero if we were stepping this LWP. */ int step; + /* If WAITSTATUS->KIND != TARGET_WAITKIND_SPURIOUS, the waitstatus + corresponding to STATUS above. */ + struct target_waitstatus waitstatus; + /* Next LWP in list. */ struct lwp_info *next; }; @@ -60,7 +66,6 @@ struct lwp_info system". */ struct mem_attrib; struct target_ops; -struct target_waitstatus; extern int linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, int write, struct mem_attrib *attrib, Index: thread-db.c =================================================================== RCS file: /cvs/src/src/gdb/thread-db.c,v retrieving revision 1.37 diff -u -p -r1.37 thread-db.c --- thread-db.c 29 Feb 2004 02:39:47 -0000 1.37 +++ thread-db.c 25 Mar 2004 16:31:31 -0000 @@ -1,6 +1,6 @@ /* libthread_db assisted debugging support, generic parts. - Copyright 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + Copyright 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -130,6 +130,7 @@ static CORE_ADDR td_death_bp_addr; static void thread_db_find_new_threads (void); static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, const td_thrinfo_t *ti_p, int verbose); +static void detach_thread (ptid_t ptid, int verbose); /* Building process ids. */ @@ -154,6 +155,8 @@ struct private_thread_info unsigned int th_valid:1; unsigned int ti_valid:1; + unsigned int dying:1; + td_thrhandle_t th; td_thrinfo_t ti; }; @@ -501,7 +504,7 @@ enable_thread_event_reporting (void) /* Set the process wide mask saying which events we're interested in. */ td_event_emptyset (&events); td_event_addset (&events, TD_CREATE); -#if 0 +#if 1 /* FIXME: kettenis/2000-04-23: The event reporting facility is broken for TD_DEATH events in glibc 2.1.3, so don't enable it for now. */ @@ -696,6 +699,20 @@ attach_thread (ptid_t ptid, const td_thr struct thread_info *tp; td_err_e err; + /* We may already know about this thread, for instance when the + user has issued the `info threads' command before the SIGTRAP + for hitting the thread creation breakpoint was reported. */ + if (in_thread_list (ptid)) + { + tp = find_thread_pid (ptid); + gdb_assert (tp != NULL); + + if (!tp->private->dying) + return; + + delete_thread (ptid); + } + check_thread_signals (); /* Add the thread to GDB's thread list. */ @@ -741,8 +758,16 @@ thread_db_attach (char *args, int from_t static void detach_thread (ptid_t ptid, int verbose) { + struct thread_info *thread_info; + if (verbose) printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid)); + + /* Don't delete the thread now, because it still reports as active until + it has executed a few instructions after the event breakpoint. */ + thread_info = find_thread_pid (ptid); + gdb_assert (thread_info != NULL); + thread_info->private->dying = 1; } static void @@ -848,11 +873,7 @@ check_event (ptid_t ptid) { case TD_CREATE: - /* We may already know about this thread, for instance when the - user has issued the `info threads' command before the SIGTRAP - for hitting the thread creation breakpoint was reported. */ - if (!in_thread_list (ptid)) - attach_thread (ptid, msg.th_p, &ti, 1); + attach_thread (ptid, msg.th_p, &ti, 1); break;