This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 3/5] libthread_db: Skip attaching to terminated and joined threads
- From: Pedro Alves <palves at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Tue, 16 Dec 2014 16:53:52 +0000
- Subject: [PATCH 3/5] libthread_db: Skip attaching to terminated and joined threads
- Authentication-results: sourceware.org; auth=none
- References: <1418748834-27545-1-git-send-email-palves at redhat dot com>
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/
2014-12-16 Pedro Alves <palves@redhat.com>
* thread-db.c (find_new_threads_callback): Ignore thread if the
kernel thread ID is -1.
gdb/
2014-12-16 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.
---
gdb/gdbserver/thread-db.c | 11 +++++++++++
gdb/linux-nat.c | 1 +
gdb/linux-thread-db.c | 11 +++++++++++
3 files changed, 23 insertions(+)
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
index ac94892..2d9980d 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 c6b5280..828064f 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 a405603..4b26984 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1606,6 +1606,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
--
1.9.3