This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC]: fix for recycled thread ids


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;
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]