This is the mail archive of the gdb-cvs@sourceware.org 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]

[binutils-gdb/users/hjl/linux/master] libthread_db: Skip attaching to terminated and joined threads


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a33e39599ce39ec6225d71f7da1719b544740745

commit a33e39599ce39ec6225d71f7da1719b544740745
Author: Pedro Alves <palves@redhat.com>
Date:   Tue Dec 16 16:12:24 2014 +0000

    libthread_db: Skip attaching to terminated and joined threads
    
    I wrote a test that attaches to a program that constantly spawns
    short-lived threads, which exposed several issues.  This is one of
    them.
    
    On GNU/Linux, attaching to a multi-threaded program sometimes prints
    out warnings like:
    
     ...
     [New LWP 20700]
     warning: unable to open /proc file '/proc/-1/status'
     [New LWP 20850]
     [New LWP 21019]
     ...
    
    That happens because when a thread exits, and is joined, glibc does:
    
    nptl/pthread_join.c:
    pthread_join ()
    {
    ...
      if (__glibc_likely (result == 0))
        {
          /* We mark the thread as terminated and as joined.  */
          pd->tid = -1;
    ...
         /* Free the TCB.  */
          __free_tcb (pd);
        }
    
    So if we attach or interrupt the program (which does an implicit "info
    threads") at just the right (or rather, wrong) time, we can find and
    return threads in the libthread_db/pthreads thread list with kernel
    thread ID -1.  I've filed glibc PR nptl/17707 for this.  You'll find
    more info there.
    
    This patch handles this as a special case in GDB.
    
    This is actually more than just a cosmetic issue.  lin_lwp_attach_lwp
    will think that this -1 is an LWP we're not attached to yet, and after
    failing to attach will try to check we were already attached to the
    process, using a waitpid call, which in this case ends up being
    "waitpid (-1, ...", which obviously results in GDB potentially
    discarding an event when it shouldn't...
    
    Tested on x86_64 Fedora 20, native and gdbserver.
    
    gdb/gdbserver/
    2015-01-09  Pedro Alves  <palves@redhat.com>
    
    	* thread-db.c (find_new_threads_callback): Ignore thread if the
    	kernel thread ID is -1.
    
    gdb/
    2015-01-09  Pedro Alves  <palves@redhat.com>
    
    	* linux-nat.c (lin_lwp_attach_lwp): Assert that the lwp id we're
    	about to wait for is > 0.
    	* linux-thread-db.c (find_new_threads_callback): Ignore thread if
    	the kernel thread ID is -1.

Diff:
---
 gdb/ChangeLog             |  7 +++++++
 gdb/gdbserver/ChangeLog   |  5 +++++
 gdb/gdbserver/thread-db.c | 11 +++++++++++
 gdb/linux-nat.c           |  1 +
 gdb/linux-thread-db.c     | 11 +++++++++++
 5 files changed, 35 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4ee17b3..fb99d26 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,12 @@
 2015-01-09  Pedro Alves  <palves@redhat.com>
 
+	* linux-nat.c (lin_lwp_attach_lwp): Assert that the lwp id we're
+	about to wait for is > 0.
+	* linux-thread-db.c (find_new_threads_callback): Ignore thread if
+	the kernel thread ID is -1.
+
+2015-01-09  Pedro Alves  <palves@redhat.com>
+
 	* linux-nat.c (attach_proc_task_lwp_callback): New function.
 	(linux_nat_attach): Use linux_proc_attach_tgid_threads.
 	(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 2ee6a00..d6bafae 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,10 @@
 2015-01-09  Pedro Alves  <palves@redhat.com>
 
+	* thread-db.c (find_new_threads_callback): Ignore thread if the
+	kernel thread ID is -1.
+
+2015-01-09  Pedro Alves  <palves@redhat.com>
+
 	* linux-low.c (linux_attach_fail_reason_string): Move to
 	nat/linux-ptrace.c, and rename.
 	(linux_attach_lwp): Update comment.
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
index 4e0d32a..b0d1f0d 100644
--- a/gdb/gdbserver/thread-db.c
+++ b/gdb/gdbserver/thread-db.c
@@ -396,6 +396,17 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
   if (err != TD_OK)
     error ("Cannot get thread info: %s", thread_db_err_str (err));
 
+  if (ti.ti_lid == -1)
+    {
+      /* A thread with kernel thread ID -1 is either a thread that
+	 exited and was joined, or a thread that is being created but
+	 hasn't started yet, and that is reusing the tcb/stack of a
+	 thread that previously exited and was joined.  (glibc marks
+	 terminated and joined threads with kernel thread ID -1.  See
+	 glibc PR17707.  */
+      return 0;
+    }
+
   /* Check for zombies.  */
   if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
     return 0;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0adf3a9..77aa8e3 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1023,6 +1023,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
 
 		  /* See if we've got a stop for this new child
 		     pending.  If so, we're already attached.  */
+		  gdb_assert (lwpid > 0);
 		  new_pid = my_waitpid (lwpid, &status, WNOHANG);
 		  if (new_pid == -1 && errno == ECHILD)
 		    new_pid = my_waitpid (lwpid, &status, __WCLONE | WNOHANG);
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index b7afb03..1417542 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1610,6 +1610,17 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
     error (_("find_new_threads_callback: cannot get thread info: %s"),
 	   thread_db_err_str (err));
 
+  if (ti.ti_lid == -1)
+    {
+      /* A thread with kernel thread ID -1 is either a thread that
+	 exited and was joined, or a thread that is being created but
+	 hasn't started yet, and that is reusing the tcb/stack of a
+	 thread that previously exited and was joined.  (glibc marks
+	 terminated and joined threads with kernel thread ID -1.  See
+	 glibc PR17707.  */
+      return 0;
+    }
+
   if (ti.ti_tid == 0)
     {
       /* A thread ID of zero means that this is the main thread, but


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