diff --git a/gdb/ChangeLog b/gdb/ChangeLog index fb99d260ff..d71375565f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2014-01-09 Pedro Alves + + 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 * linux-nat.c (lin_lwp_attach_lwp): Assert that the lwp id we're diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index 1417542a6b..156cfe75e2 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -38,6 +38,7 @@ #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" @@ -77,6 +78,16 @@ static char *libthread_db_search_path; 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 @@ -836,7 +847,7 @@ try_thread_db_load_1 (struct thread_db_info *info) 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; @@ -1264,6 +1275,17 @@ thread_db_inferior_created (struct target_ops *target, int from_tty) 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. */ @@ -1345,8 +1367,7 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, 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) @@ -1358,7 +1379,7 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, /* 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) @@ -1397,7 +1418,7 @@ thread_db_detach (struct target_ops *ops, const char *args, int from_tty) if (info) { - if (target_has_execution) + if (target_has_execution && thread_db_use_events ()) { disable_thread_event_reporting (info); @@ -1633,7 +1654,7 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data) 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) @@ -1670,6 +1691,12 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data) 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; } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1a676409e4..d44bee563d 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2014-01-09 Pedro Alves + + * gdb.threads/fork-thread-pending.exp: Switch to the main thread + instead of to thread 2. + * gdb.threads/signal-command-multiple-signals-pending.c (main): + Add barrier around each pthread_create call instead of around all + calls. + * gdb.threads/signal-command-multiple-signals-pending.exp (test): + Set a break on thread_function and have the child threads hit it + one at at a time. + 2015-01-09 Pedro Alves * lib/gdb.exp (can_spawn_for_attach): New procedure. diff --git a/gdb/testsuite/gdb.threads/fork-thread-pending.exp b/gdb/testsuite/gdb.threads/fork-thread-pending.exp index f7727c62f1..d229232415 100644 --- a/gdb/testsuite/gdb.threads/fork-thread-pending.exp +++ b/gdb/testsuite/gdb.threads/fork-thread-pending.exp @@ -46,7 +46,7 @@ gdb_test "continue" "Catchpoint.*" "1, get to the fork event" gdb_test "info threads" " Thread .* Thread .* Thread .* Thread .*" "1, multiple threads found" -gdb_test "thread 2" ".*" "1, switched away from event thread" +gdb_test "thread 1" ".*" "1, switched away from event thread" gdb_test "continue" "Not resuming.*" "1, refused to resume" diff --git a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c index 0f17fb75d4..5f5865da48 100644 --- a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c +++ b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c @@ -76,12 +76,13 @@ main (void) 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 (); diff --git a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp index 7cc3702ebc..8938ee04a8 100644 --- a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp +++ b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp @@ -46,6 +46,13 @@ proc test { schedlock } { gdb_test "handle SIGUSR2 stop print pass" gdb_test "break all_threads_started" "Breakpoint .* at .*$srcfile.*" + + # Create threads one at a time, to insure stable thread + # numbers between runs and targets. + gdb_test "break thread_function" "Breakpoint .* at .*$srcfile.*" + gdb_test "continue" "thread_function.*" "thread 2 created" + gdb_test "continue" "thread_function.*" "thread 3 created" + gdb_test "continue" "all_threads_started.*" # Using schedlock, let the main thread queue a signal for each