* linux-nat.h (linux_proc_get_tgid): Declare.
authorPedro Alves <palves@redhat.com>
Mon, 18 May 2009 17:11:25 +0000 (17:11 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 18 May 2009 17:11:25 +0000 (17:11 +0000)
* linux-nat.c (linux_proc_get_tgid): New.
* linux-thread-db.c (struct thread_db_info): New field
`need_stale_parent_threads_check'.
(add_thread_db_info): Set it.
(find_new_threads_callback): Ignore stale fork parent threads.
(thread_db_resume): New.
(init_thread_db_ops): Install thread_db_resume.

gdb/ChangeLog
gdb/linux-nat.c
gdb/linux-nat.h
gdb/linux-thread-db.c

index 7b234b9..854070b 100644 (file)
@@ -1,5 +1,16 @@
 2009-05-18  Pedro Alves  <pedro@codesourcery.com>
 
+       * linux-nat.h (linux_proc_get_tgid): Declare.
+       * linux-nat.c (linux_proc_get_tgid): New.
+       * linux-thread-db.c (struct thread_db_info): New field
+       `need_stale_parent_threads_check'.
+       (add_thread_db_info): Set it.
+       (find_new_threads_callback): Ignore stale fork parent threads.
+       (thread_db_resume): New.
+       (init_thread_db_ops): Install thread_db_resume.
+
+2009-05-18  Pedro Alves  <pedro@codesourcery.com>
+
        * 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
index 553d676..c3aa94f 100644 (file)
@@ -1129,6 +1129,34 @@ exit_lwp (struct lwp_info *lp)
   delete_lwp (lp->ptid);
 }
 
+/* Return an lwp's tgid, found in `/proc/PID/status'.  */
+
+int
+linux_proc_get_tgid (int lwpid)
+{
+  FILE *status_file;
+  char buf[100];
+  int tgid = -1;
+
+  snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
+  status_file = fopen (buf, "r");
+  if (status_file != NULL)
+    {
+      while (fgets (buf, sizeof (buf), status_file))
+       {
+         if (strncmp (buf, "Tgid:", 5) == 0)
+           {
+             tgid = strtoul (buf + strlen ("Tgid:"), NULL, 10);
+             break;
+           }
+       }
+
+      fclose (status_file);
+    }
+
+  return tgid;
+}
+
 /* Detect `T (stopped)' in `/proc/PID/status'.
    Other states including `T (tracing stop)' are reported as false.  */
 
index 5c17425..d1ed6fc 100644 (file)
@@ -99,6 +99,10 @@ 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);
 
+/* Return the TGID of LWPID from /proc/pid/status.  Returns -1 if not
+   found.  */
+extern int linux_proc_get_tgid (int lwpid);
+
 /* linux-nat functions for handling fork events.  */
 extern void linux_enable_event_reporting (ptid_t ptid);
 
index 6e68965..3efcae8 100644 (file)
@@ -104,6 +104,13 @@ struct thread_db_info
   /* Connection to the libthread_db library.  */
   td_thragent_t *thread_agent;
 
+  /* True if we need to apply the workaround for glibc/BZ5983.  When
+     we catch a PTRACE_O_TRACEFORK, and go query the child's thread
+     list, nptl_db returns the parent's threads in addition to the new
+     (single) child thread.  If this flag is set, we do extra work to
+     be able to ignore such stale entries.  */
+  int need_stale_parent_threads_check;
+
   /* Location of the thread creation event breakpoint.  The code at
      this location in the child process will be called by the pthread
      library whenever a new thread is created.  By setting a special
@@ -168,6 +175,7 @@ add_thread_db_info (void *handle)
   info = xcalloc (1, sizeof (*info));
   info->pid = ptid_get_pid (inferior_ptid);
   info->handle = handle;
+  info->need_stale_parent_threads_check = 1;
 
   info->next = thread_db_list;
   thread_db_list = info;
@@ -1269,8 +1277,6 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
   if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
     return 0;                  /* A zombie -- ignore.  */
 
-  ptid = ptid_build (info->pid, ti.ti_lid, 0);
-
   if (ti.ti_tid == 0)
     {
       /* A thread ID of zero means that this is the main thread, but
@@ -1279,14 +1285,29 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
         be yet.  Just enable event reporting and otherwise ignore
         it.  */
 
+      /* In that case, we're not stopped in a fork syscall and don't
+        need this glibc bug workaround.  */
+      info->need_stale_parent_threads_check = 0;
+
       err = info->td_thr_event_enable_p (th_p, 1);
       if (err != TD_OK)
-       error (_("Cannot enable thread event reporting for %s: %s"),
-              target_pid_to_str (ptid), thread_db_err_str (err));
+       error (_("Cannot enable thread event reporting for LWP %d: %s"),
+              (int) ti.ti_lid, thread_db_err_str (err));
 
       return 0;
     }
 
+  /* Ignore stale parent threads, caused by glibc/BZ5983.  This is a
+     bit expensive, as it needs to open /proc/pid/status, so try to
+     avoid doing the work if we know we don't have to.  */
+  if (info->need_stale_parent_threads_check)
+    {
+      int tgid = linux_proc_get_tgid (ti.ti_lid);
+      if (tgid != -1 && tgid != info->pid)
+       return 0;
+    }
+
+  ptid = ptid_build (info->pid, ti.ti_lid, 0);
   tp = find_thread_pid (ptid);
   if (tp == NULL || tp->private == NULL)
     attach_thread (ptid, th_p, &ti);
@@ -1480,6 +1501,27 @@ thread_db_get_ada_task_ptid (long lwp, long thread)
 }
 
 static void
+thread_db_resume (struct target_ops *ops,
+                 ptid_t ptid, int step, enum target_signal signo)
+{
+  struct target_ops *beneath = find_target_beneath (ops);
+  struct thread_db_info *info;
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    info = get_thread_db_info (GET_PID (inferior_ptid));
+  else
+    info = get_thread_db_info (GET_PID (ptid));
+
+  /* This workaround is only needed for child fork lwps stopped in a
+     PTRACE_O_TRACEFORK event.  When the inferior is resumed, the
+     workaround can be disabled.  */
+  if (info)
+    info->need_stale_parent_threads_check = 0;
+
+  beneath->to_resume (beneath, ptid, step, signo);
+}
+
+static void
 init_thread_db_ops (void)
 {
   thread_db_ops.to_shortname = "multi-thread";
@@ -1487,6 +1529,7 @@ init_thread_db_ops (void)
   thread_db_ops.to_doc = "Threads and pthreads support.";
   thread_db_ops.to_detach = thread_db_detach;
   thread_db_ops.to_wait = thread_db_wait;
+  thread_db_ops.to_resume = thread_db_resume;
   thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
   thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
   thread_db_ops.to_pid_to_str = thread_db_pid_to_str;