+2014-01-09 Pedro Alves <palves@redhat.com>
+
+ Skip enabling event reporting if the kernel supports
+ PTRACE_EVENT_CLONE.
+ * linux-thread-db.c: Include "nat/linux-ptrace.h".
+ (thread_db_use_events): New function.
+ (try_thread_db_load_1): Check thread_db_use_events before enabling
+ event reporting.
+ (update_thread_state): New function.
+ (attach_thread): Use it. Check thread_db_use_events before
+ enabling event reporting.
+ (thread_db_detach): Check thread_db_use_events before disabling
+ event reporting.
+ (find_new_threads_callback): Check thread_db_use_events before
+ enabling event reporting. Update the thread's state if not using
+ libthread_db events.
+
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (lin_lwp_attach_lwp): Assert that the lwp id we're
#include "observer.h"
#include "linux-nat.h"
#include "nat/linux-procfs.h"
+#include "nat/linux-ptrace.h"
#include "nat/linux-osdata.h"
#include "auto-load.h"
#include "cli/cli-utils.h"
by the "set auto-load libthread-db" command. */
static int auto_load_thread_db = 1;
+/* Returns true if we need to use thread_db thread create/death event
+ breakpoints to learn about threads. */
+
+static int
+thread_db_use_events (void)
+{
+ /* Not necessary if the kernel supports clone events. */
+ return !linux_supports_traceclone ();
+}
+
/* "show" command for the auto_load_thread_db configuration variable. */
static void
push_target (&thread_db_ops);
/* Enable event reporting, but not when debugging a core file. */
- if (target_has_execution)
+ if (target_has_execution && thread_db_use_events ())
enable_thread_event_reporting ();
return 1;
check_for_thread_db ();
}
+/* Update the thread's state (what's displayed in "info threads"),
+ from libthread_db thread state information. */
+
+static void
+update_thread_state (struct private_thread_info *private,
+ const td_thrinfo_t *ti_p)
+{
+ private->dying = (ti_p->ti_state == TD_THR_UNKNOWN
+ || ti_p->ti_state == TD_THR_ZOMBIE);
+}
+
/* Attach to a new thread. This function is called when we receive a
TD_CREATE event or when we iterate over all threads and find one
that wasn't already in our list. Returns true on success. */
gdb_assert (ti_p->ti_tid != 0);
private->th = *th_p;
private->tid = ti_p->ti_tid;
- if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
- private->dying = 1;
+ update_thread_state (private, ti_p);
/* Add the thread to GDB's thread list. */
if (tp == NULL)
/* Enable thread event reporting for this thread, except when
debugging a core file. */
- if (target_has_execution)
+ if (target_has_execution && thread_db_use_events ())
{
err = info->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK)
if (info)
{
- if (target_has_execution)
+ if (target_has_execution && thread_db_use_events ())
{
disable_thread_event_reporting (info);
need this glibc bug workaround. */
info->need_stale_parent_threads_check = 0;
- if (target_has_execution)
+ if (target_has_execution && thread_db_use_events ())
{
err = info->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK)
iteration: thread_db_find_new_threads_2 will retry. */
return 1;
}
+ else if (target_has_execution && !thread_db_use_events ())
+ {
+ /* Need to update this if not using the libthread_db events
+ (particularly, the TD_DEATH event). */
+ update_thread_state (tp->private, &ti);
+ }
return 0;
}
signal (SIGUSR1, handler_sigusr1);
signal (SIGUSR2, handler_sigusr2);
- pthread_barrier_init (&barrier, NULL, 3);
-
for (i = 0; i < 2; i++)
- pthread_create (&child_thread[i], NULL, thread_function, NULL);
-
- pthread_barrier_wait (&barrier);
+ {
+ pthread_barrier_init (&barrier, NULL, 2);
+ pthread_create (&child_thread[i], NULL, thread_function, NULL);
+ pthread_barrier_wait (&barrier);
+ pthread_barrier_destroy (&barrier);
+ }
all_threads_started ();