diff options
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/watchthreads2.c | 115 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/watchthreads2.exp | 139 |
3 files changed, 259 insertions, 0 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8e8744b..83409c7 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-04-30 Doug Evans <dje@google.com> + + * gdb.threads/watchthreads2.exp: New testcase. + * gdb.threads/watchthreads2.c: New testcase. + 2009-04-29 Doug Evans <dje@google.com> * gdb.cp/mb-ctor.exp: Add multi-line source statement test. diff --git a/gdb/testsuite/gdb.threads/watchthreads2.c b/gdb/testsuite/gdb.threads/watchthreads2.c new file mode 100644 index 0000000..8df97fd --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchthreads2.c @@ -0,0 +1,115 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Check that watchpoints get propagated to all existing threads when the + watchpoint is created. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef NR_THREADS +#define NR_THREADS 4 +#endif + +#ifndef X_INCR_COUNT +#define X_INCR_COUNT 10 +#endif + +void *thread_function (void *arg); /* Function executed by each thread. */ + +pthread_mutex_t x_mutex; +int x; + +/* Used to hold threads back until watchthreads2.exp is ready. */ +int test_ready = 0; + +int +main () +{ + int res; + pthread_t threads[NR_THREADS]; + int i; + + pthread_mutex_init (&x_mutex, NULL); + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_create (&threads[i], + NULL, + thread_function, + (void *) (intptr_t) i); + if (res != 0) + { + fprintf (stderr, "error in thread %d create\n", i); + abort (); + } + } + + for (i = 0; i < NR_THREADS; ++i) + { + res = pthread_join (threads[i], NULL); + if (res != 0) + { + fprintf (stderr, "error in thread %d join\n", i); + abort (); + } + } + + exit (EXIT_SUCCESS); +} + +/* Easy place for a breakpoint. + watchthreads2.exp uses this to track when all threads are running + instead of, for example, the program keeping track + because we don't need the program to know when all threads are running, + instead we need gdb to know when all threads are running. + There is a delay between when a thread has started and when the thread + has been registered with gdb. */ + +void +thread_started () +{ +} + +void * +thread_function (void *arg) +{ + int i; + + thread_started (); + + /* Don't start incrementing X until watchthreads2.exp is ready. */ + while (! test_ready) + usleep (1); + + for (i = 0; i < X_INCR_COUNT; ++i) + { + pthread_mutex_lock (&x_mutex); + /* For debugging. */ + printf ("Thread %ld changing x %d -> %d\n", (long) arg, x, x + 1); + /* The call to usleep is so that when the watchpoint triggers, + the pc is still on the same line. */ + ++x; usleep (1); /* X increment. */ + pthread_mutex_unlock (&x_mutex); + } + + pthread_exit (NULL); +} diff --git a/gdb/testsuite/gdb.threads/watchthreads2.exp b/gdb/testsuite/gdb.threads/watchthreads2.exp new file mode 100644 index 0000000..06d980e --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchthreads2.exp @@ -0,0 +1,139 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that watchpoints get propagated to all existing threads when the +# watchpoint is created. + +set NR_THREADS 4 +set X_INCR_COUNT 10 + +if $tracelevel { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +# This test verifies that a watchpoint is detected in the proper thread +# so the test is only meaningful on a system with hardware watchpoints. +if [target_info exists gdb,no_hardware_watchpoints] { + return 0; +} + +set testfile "watchthreads2" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}" "additional_flags=-DNR_THREADS=$NR_THREADS -DX_INCR_COUNT=$X_INCR_COUNT"]] != "" } { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test "set can-use-hw-watchpoints 1" "" "" + +# +# Run to `main' where we begin our tests. +# + +if ![runto_main] then { + gdb_suppress_tests +} + +gdb_test "break thread_started" \ + "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ + "breakpoint on thread_started" + +# Run the program until all threads have hit thread_started. +# We use this as the vehicle to determine when gdb is aware +# of all threads (i.e. "info threads" would show all threads). + +set nr_started 0 +set message "run to thread_started" +for { set i 0 } { $i < $NR_THREADS } { incr i } { + gdb_test_multiple "continue" $message { + -re ".*Breakpoint 2, thread_started ().*$gdb_prompt $" { + incr nr_started + } + timeout { + set i $NR_THREADS + } + } +} +if { $nr_started == $NR_THREADS } { + pass "all threads started" +} else { + fail "all threads started" + # No point in continuing. + return -1 +} + +# Watch X, it will be modified by all threads. +# We want this watchpoint to be set *after* all threads are running. +gdb_test "watch x" "Hardware watchpoint 3: x" + +# Now that the watchpoint is set, we can let the threads increment X. +gdb_test "set var test_ready = 1" "" + +# While debugging. +#gdb_test "set debug infrun 1" "" + +set x_inc_line [gdb_get_line_number "X increment"] +set x_thread_loc "thread_function \\\(arg=.*\\\) at .*watchthreads.c:$x_inc_line" + +# X is incremented under a mutex, so we should get NR_THREADS * X_INCR_COUNT +# hits. +set limit [expr $NR_THREADS*$X_INCR_COUNT] +set x_count 0 +set done 0 + +set message "x watch loop" + +for {set i 0} {!$done && $i < $limit} {incr i} { + set test_flag 0 + + gdb_test_multiple "continue" $message { + -re "(.*Hardware watchpoint.*)$gdb_prompt $" { + set string $expect_out(1,string) + + if [regexp "Hardware watchpoint 3: x\[^\r\]*\r\[^\r\]*\r\[^\r\]*Old value = $x_count\[^\r\]*\r\[^\r\]*New value = [expr $x_count+1]\r" $string] { + incr x_count + set test_flag 1 + } else { + # We test for new value = old value + 1 each iteration. + # This can fail due to gdb/10116. + # This is caught after the loop exits. + } + } + -re "The program is not being run.*$gdb_prompt $" { + fail "$message (program terminated)" + } + } + + # If we fail above, don't bother continuing loop. + if { $test_flag == 0 } { + set done 1 + } +} + +if { $i == $limit } { + pass "all threads incremented x" +} else { + kfail "gdb/10116" "gdb can drop watchpoints in multithreaded app" +} |