* 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.
This commit is contained in:
Pedro Alves
2009-05-18 17:11:25 +00:00
parent d90e17a74d
commit 4d062f1ad5
4 changed files with 90 additions and 4 deletions

View File

@ -1,3 +1,14 @@
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> 2009-05-18 Pedro Alves <pedro@codesourcery.com>
* fork-child.c (fork_inferior): Only reset the thread list if this * fork-child.c (fork_inferior): Only reset the thread list if this

View File

@ -1129,6 +1129,34 @@ exit_lwp (struct lwp_info *lp)
delete_lwp (lp->ptid); 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'. /* Detect `T (stopped)' in `/proc/PID/status'.
Other states including `T (tracing stop)' are reported as false. */ Other states including `T (tracing stop)' are reported as false. */

View File

@ -99,6 +99,10 @@ int thread_db_attach_lwp (ptid_t ptid);
/* Find process PID's pending signal set from /proc/pid/status. */ /* 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); 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. */ /* linux-nat functions for handling fork events. */
extern void linux_enable_event_reporting (ptid_t ptid); extern void linux_enable_event_reporting (ptid_t ptid);

View File

@ -104,6 +104,13 @@ struct thread_db_info
/* Connection to the libthread_db library. */ /* Connection to the libthread_db library. */
td_thragent_t *thread_agent; 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 /* Location of the thread creation event breakpoint. The code at
this location in the child process will be called by the pthread this location in the child process will be called by the pthread
library whenever a new thread is created. By setting a special 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 = xcalloc (1, sizeof (*info));
info->pid = ptid_get_pid (inferior_ptid); info->pid = ptid_get_pid (inferior_ptid);
info->handle = handle; info->handle = handle;
info->need_stale_parent_threads_check = 1;
info->next = thread_db_list; info->next = thread_db_list;
thread_db_list = info; 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) if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
return 0; /* A zombie -- ignore. */ return 0; /* A zombie -- ignore. */
ptid = ptid_build (info->pid, ti.ti_lid, 0);
if (ti.ti_tid == 0) if (ti.ti_tid == 0)
{ {
/* A thread ID of zero means that this is the main thread, but /* 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 be yet. Just enable event reporting and otherwise ignore
it. */ 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); err = info->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK) if (err != TD_OK)
error (_("Cannot enable thread event reporting for %s: %s"), error (_("Cannot enable thread event reporting for LWP %d: %s"),
target_pid_to_str (ptid), thread_db_err_str (err)); (int) ti.ti_lid, thread_db_err_str (err));
return 0; 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); tp = find_thread_pid (ptid);
if (tp == NULL || tp->private == NULL) if (tp == NULL || tp->private == NULL)
attach_thread (ptid, th_p, &ti); attach_thread (ptid, th_p, &ti);
@ -1479,6 +1500,27 @@ thread_db_get_ada_task_ptid (long lwp, long thread)
return (thread_info->ptid); return (thread_info->ptid);
} }
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 static void
init_thread_db_ops (void) init_thread_db_ops (void)
{ {
@ -1487,6 +1529,7 @@ init_thread_db_ops (void)
thread_db_ops.to_doc = "Threads and pthreads support."; thread_db_ops.to_doc = "Threads and pthreads support.";
thread_db_ops.to_detach = thread_db_detach; thread_db_ops.to_detach = thread_db_detach;
thread_db_ops.to_wait = thread_db_wait; 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_mourn_inferior = thread_db_mourn_inferior;
thread_db_ops.to_find_new_threads = thread_db_find_new_threads; thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
thread_db_ops.to_pid_to_str = thread_db_pid_to_str; thread_db_ops.to_pid_to_str = thread_db_pid_to_str;