From: Daniel Jacobowitz Date: Fri, 23 Aug 2002 20:32:02 +0000 (+0000) Subject: * gdb.threads/print-threads.c: New file. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0312286c94c3e88ca30ea61f5fe60e4fb24d0aa1;p=binutils-gdb.git * gdb.threads/print-threads.c: New file. * gdb.threads/print-threads.exp: New file. * gdb.threads/schedlock.c: New file. * gdb.threads/schedlock.exp: New file. --- diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e8d14ab558d..e47afec868b 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2002-08-23 Daniel Jacobowitz + + * gdb.threads/print-threads.c: New file. + * gdb.threads/print-threads.exp: New file. + * gdb.threads/schedlock.c: New file. + * gdb.threads/schedlock.exp: New file. + 2002-08-22 Elena Zannoni * gdb.arch/altivec-abi.exp: The source C file is altivec-abi.c, diff --git a/gdb/testsuite/gdb.threads/print-threads.c b/gdb/testsuite/gdb.threads/print-threads.c new file mode 100644 index 00000000000..341ee0aa35a --- /dev/null +++ b/gdb/testsuite/gdb.threads/print-threads.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +void *thread_function(void *arg); /* Pointer to function executed by each thread */ + +int slow = 0; + +#define NUM 5 + +int main() { + int res; + pthread_t threads[NUM]; + void *thread_result; + int args[NUM]; + int i; + + for (i = 0; i < NUM; i++) + { + args[i] = i; + res = pthread_create(&threads[i], NULL, thread_function, (void *)&args[i]); + } + + for (i = 0; i < NUM; i++) + res = pthread_join(threads[i], &thread_result); + + printf ("Done\n"); + + if (slow) + sleep (4); + + exit(EXIT_SUCCESS); +} + +void *thread_function(void *arg) { + int my_number = *(int *)arg; + int rand_num; + + printf ("Print 1, thread %d\n", my_number); + sleep (1); + + if (slow) + { + printf ("Print 2, thread %d\n", my_number); + sleep (1); + printf ("Print 3, thread %d\n", my_number); + sleep (1); + printf ("Print 4, thread %d\n", my_number); + sleep (1); + printf ("Print 5, thread %d\n", my_number); + sleep (1); + } + + printf("Bye from %d\n", my_number); + pthread_exit(NULL); +} + diff --git a/gdb/testsuite/gdb.threads/print-threads.exp b/gdb/testsuite/gdb.threads/print-threads.exp new file mode 100644 index 00000000000..09c3f8ada80 --- /dev/null +++ b/gdb/testsuite/gdb.threads/print-threads.exp @@ -0,0 +1,156 @@ +# Copyright (C) 1996, 1997, 2002 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was written by Daniel Jacobowitz +# (parts based on pthreads.exp by Fred Fish (fnf@cygnus.com). +# +# It tests miscellaneous actions with multiple threads, including +# handling for thread exit. + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile "print-threads" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# regexp for "horizontal" text (i.e. doesn't include newline or +# carriage return) +set horiz "\[^\n\r\]*" + +set built_binfile 0 + +# Default to the usual (only?) -lpthread on GNU/Linux to quiet noise +if [istarget "*-*-linux*"] then { + set possible_libs "-lpthread -lpthreads -lthread" +} else { + set possible_libs "-lpthreads -lpthread -lthread" +} + +set why_msg "unrecognized error" +foreach lib $possible_libs { + set options "debug" + lappend options "incdir=${objdir}/${subdir}" + lappend options "libs=$lib" + set ccout [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $options] + switch -regexp -- $ccout { + ".*no posix threads support.*" { + set why_msg "missing threads include file" + break + } + ".*cannot open -lpthread.*" { + set why_msg "missing runtime threads library" + } + ".*Can't find library for -lpthread.*" { + set why_msg "missing runtime threads library" + } + {^$} { + pass "successfully compiled posix threads test case" + set built_binfile 1 + break + } + } +} +if {$built_binfile == "0"} { + unsupported "Couldn't compile ${srcfile}, ${why_msg}" + return -1 +} + +# Now we can proceed with the real testing. + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test "set print sevenbit-strings" "" +#gdb_test "set print address off" "" +gdb_test "set width 0" "" + +# We'll need this when we send_gdb a ^C to GDB. Need to do it before we +# run the program and gdb starts saving and restoring tty states. +# On Ultrix, we don't need it and it is really slow (because shell_escape +# doesn't use vfork). +if ![istarget "*-*-ultrix*"] then { + gdb_test "shell stty intr '^C'" "" +} + +proc test_all_threads { name kill } { + global gdb_prompt + + set i 0 + set j 0 + send_gdb "continue\n" + gdb_expect { + -re "Breakpoint \[0-9\]+, thread_function \\(arg=.*\\) at .*print-threads.c:\[0-9\]+.*$gdb_prompt" { + set i [expr $i + 1] + pass "Hit thread_function breakpoint, $i ($name)" + send_gdb "continue\n" + exp_continue + } + -re "Breakpoint \[0-9\]+, .* kill \\(.*\\) .*$gdb_prompt" { + set j [expr $j + 1] + if { $kill == 1 } { + pass "Hit kill breakpoint, $j ($name)" + } else { + fail "Hit kill breakpoint, $j ($name) (unexpected)" + } + send_gdb "continue\n" + exp_continue + } + -re "Program exited normally\\.\[\r\n\]+$gdb_prompt" { + pass "program exited normally" + if {$i == 5} { + pass "all threads ran once ($name)" + } else { + fail "all threads ran once ($name) (total $i threads ran)" + } + } + -re "$gdb_prompt" { + fail "Running threads ($name) (unknown output)" + } + timeout { + fail "Running threads ($name) (timeout)" + } + } +} + +runto_main +gdb_test "break thread_function" "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*print-threads.c, line \[0-9\]*\\." +gdb_test "set var slow = 0" "" +test_all_threads "fast" 0 + +runto_main +gdb_test "break thread_function" "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*print-threads.c, line \[0-9\]*\\." "break thread_function (2)" +gdb_test "set var slow = 1" "" +test_all_threads "slow" 0 + +runto_main +gdb_test "break thread_function" "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*print-threads.c, line \[0-9\]*\\." "break thread_function (3)" +gdb_test "set var slow = 1" "" "set var slow = 1 (2)" +gdb_test "break kill" "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+" +test_all_threads "slow with kill breakpoint" 1 + +return 0 diff --git a/gdb/testsuite/gdb.threads/schedlock.c b/gdb/testsuite/gdb.threads/schedlock.c new file mode 100644 index 00000000000..df361d0e0a7 --- /dev/null +++ b/gdb/testsuite/gdb.threads/schedlock.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +void *thread_function(void *arg); /* Pointer to function executed by each thread */ + +#define NUM 5 + +int args[NUM+1]; + +int main() { + int res; + pthread_t threads[NUM]; + void *thread_result; + int i; + + for (i = 0; i < NUM; i++) + { + args[i] = 1; + res = pthread_create(&threads[i], NULL, thread_function, (void *)i); + } + + /* schedlock.exp: last thread start. */ + args[i] = 1; + thread_function ((void *) i); + + exit(EXIT_SUCCESS); +} + +void *thread_function(void *arg) { + int my_number = (int) arg; + int *myp = &args[my_number]; + + /* Don't run forever. Run just short of it :) */ + while (*myp > 0) + { + /* schedlock.exp: main loop. */ + (*myp) ++; + } + + pthread_exit(NULL); +} + diff --git a/gdb/testsuite/gdb.threads/schedlock.exp b/gdb/testsuite/gdb.threads/schedlock.exp new file mode 100644 index 00000000000..ea2d8d3fdc6 --- /dev/null +++ b/gdb/testsuite/gdb.threads/schedlock.exp @@ -0,0 +1,353 @@ +# Copyright (C) 1996, 1997, 2002 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 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was written by Daniel Jacobowitz +# (parts based on pthreads.exp by Fred Fish (fnf@cygnus.com). +# +# This test covers the various forms of "set scheduler-locking". + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile "schedlock" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +set built_binfile 0 + +# Default to the usual (only?) -lpthread on GNU/Linux to quiet noise +if [istarget "*-*-linux*"] then { + set possible_libs "-lpthread -lpthreads -lthread" +} else { + set possible_libs "-lpthreads -lpthread -lthread" +} + +set why_msg "unrecognized error" +foreach lib $possible_libs { + set options "debug" + lappend options "incdir=${objdir}/${subdir}" + lappend options "libs=$lib" + set ccout [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $options] + switch -regexp -- $ccout { + ".*no posix threads support.*" { + set why_msg "missing threads include file" + break + } + ".*cannot open -lpthread.*" { + set why_msg "missing runtime threads library" + } + ".*Can't find library for -lpthread.*" { + set why_msg "missing runtime threads library" + } + {^$} { + pass "successfully compiled posix threads test case" + set built_binfile 1 + break + } + } +} +if {$built_binfile == "0"} { + unsupported "Couldn't compile ${srcfile}, ${why_msg}" + return -1 +} + +# Now we can proceed with the real testing. + +proc get_args { } { + global list_count + global gdb_prompt + + send_gdb "print args\n" + gdb_expect { + -re "\\\$\[0-9\]+ = {(\[0-9\]+), (\[0-9\]+), (\[0-9\]+), (\[0-9\]+), (\[0-9\]+), (\[0-9\]+)}.*$gdb_prompt" + { + set list_count [expr $list_count + 1] + pass "listed args ($list_count)" + return [list $expect_out(1,string) $expect_out(2,string) $expect_out(3,string) $expect_out(4,string) $expect_out(5,string) $expect_out(6,string)] + } + -re "$gdb_prompt" + { + fail "listed args ($list_count) (unknown output)" + } + timeout + { + fail "listed args ($list_count) (timeout)" + } + } +} + +proc stop_process { description } { + global gdb_prompt + + # For this to work we must be sure to consume the "Continuing." + # message first, or GDB's signal handler may not be in place. + after 1000 {send_gdb "\003"} + gdb_expect { + -re "Program received signal SIGINT.*$gdb_prompt $" + { + pass $description + } + timeout + { + fail "$description (timeout)" + } + } +} + +proc get_current_thread { description } { + global gdb_prompt + + send_gdb "bt\n" + gdb_expect { + -re "thread_function \\(arg=0x(\[0-9\])\\).*$gdb_prompt $" + { + pass $description + return $expect_out(1,string) + } + -re "$gdb_prompt $" + { + fail "$description (unknown output)" + } + timeout + { + fail "$description (timeout)" + } + } +} + +proc my_continue { msg } { + send_gdb "continue\n" + gdb_expect { + -re "Continuing" + { pass "continue ($msg)" } + timeout + { fail "continue ($msg) (timeout)" } + } + + stop_process "stop all threads ($msg)" + + # Make sure we're in one of the looping threads. + gdb_breakpoint [gdb_get_line_number "schedlock.exp: main loop"] + gdb_continue_to_breakpoint "return to loop ($msg)" + delete_breakpoints +} + +proc step_ten_loops { msg } { + global gdb_prompt + + for {set i 0} {[expr $i < 10]} {set i [expr $i + 1]} { + send_gdb "step\n" + set other_step 0 + gdb_expect { + -re ".*myp\\) \\+\\+;\[\r\n\]+$gdb_prompt $" { + pass "step to increment ($msg $i)" + } + -re "$gdb_prompt $" { + if {$other_step == 0} { + set other_step 1 + send_gdb "step\n" + exp_continue + } else { + fail "step to increment ($msg $i)" + # FIXME cascade? + } + } + timeout { + fail "step to increment ($msg $i) (timeout)" + } + } + } +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +# We'll need this when we send_gdb a ^C to GDB. Need to do it before we +# run the program and gdb starts saving and restoring tty states. +# On Ultrix, we don't need it and it is really slow (because shell_escape +# doesn't use vfork). +if ![istarget "*-*-ultrix*"] then { + gdb_test "shell stty intr '^C'" "" +} + +gdb_load ${binfile} + +gdb_test "set print sevenbit-strings" "" +gdb_test "set width 0" "" + +runto_main + +# See if scheduler locking is available on this target. +send_gdb "set scheduler-locking off\n" +global gdb_prompt +gdb_expect { + -re "Target .* cannot support this command" + { + unsupported "target does not support scheduler locking" + return + } + -re "$gdb_prompt $" + { + pass "scheduler locking set to none" + } + timeout + { + unsupported "target does not support scheduler locking (timeout)" + return + } +} + +gdb_breakpoint [gdb_get_line_number "schedlock.exp: last thread start"] +gdb_continue_to_breakpoint "all threads started" + +global list_count +set list_count 0 + +set start_args [get_args] + +# First make sure that all threads are alive. +my_continue "initial" + +set cont_args [get_args] + +for {set i 0} {[expr $i < 6]} {set i [expr $i + 1]} { + if {[lindex $start_args $i] == [lindex $cont_args $i]} { + fail "thread $i ran (didn't run)" + } else { + pass "thread $i ran" + } +} + +# We can't change threads, unfortunately, in current GDB. Use +# whichever we stopped in. +set curthread [get_current_thread "find current thread (1)"] + + + + +# Test stepping without scheduler locking. +gdb_test "set scheduler-locking off" "" + +step_ten_loops "unlocked" + +# Make sure we're still in the same thread. +set newthread [get_current_thread "find current thread (2)"] +if {$curthread == $newthread} { + pass "step without lock does not change thread" +} else { + fail "step without lock does not change thread (switched to thread $newthread)" +} + +set start_args $cont_args +set cont_args [get_args] + +for {set i 0} {[expr $i < 6]} {set i [expr $i + 1]} { + if {[lindex $start_args $i] == [lindex $cont_args $i]} { + if {$i == $curthread} { + fail "current thread stepped (didn't run)" + } else { + fail "other thread $i ran (didn't run) (1)" + } + } else { + if {$i == $curthread} { + if {[lindex $start_args $i] == [expr [lindex $cont_args $i] - 10]} { + pass "current thread stepped" + } else { + fail "current thread stepped (wrong amount)" + } + } else { + pass "other thread $i ran (1)" + } + } +} + +# Test continue with scheduler locking +gdb_test "set scheduler-locking on" "" + +my_continue "with lock" + +# Make sure we're still in the same thread. +set newthread [get_current_thread "find current thread (3)"] +if {$curthread == $newthread} { + pass "continue with lock does not change thread" +} else { + fail "continue with lock does not change thread (switched to thread $newthread)" +} + +set start_args $cont_args +set cont_args [get_args] + +for {set i 0} {[expr $i < 6]} {set i [expr $i + 1]} { + if {[lindex $start_args $i] == [lindex $cont_args $i]} { + if {$i == $curthread} { + fail "current thread ran (didn't run)" + } else { + pass "other thread $i didn't run" + } + } else { + if {$i == $curthread} { + pass "current thread ran" + } else { + fail "other thread $i didn't run (ran)" + } + } +} + +# Test stepping with scheduler locking +step_ten_loops "locked" + +# Make sure we're still in the same thread. +set newthread [get_current_thread "find current thread (2)"] +if {$curthread == $newthread} { + pass "step with lock does not change thread" +} else { + fail "step with lock does not change thread (switched to thread $newthread)" +} + +set start_args $cont_args +set cont_args [get_args] + +for {set i 0} {[expr $i < 6]} {set i [expr $i + 1]} { + if {[lindex $start_args $i] == [lindex $cont_args $i]} { + if {$i == $curthread} { + fail "current thread stepped locked (didn't run)" + } else { + pass "other thread $i didn't run (stepping)" + } + } else { + if {$i == $curthread} { + if {[lindex $start_args $i] == [expr [lindex $cont_args $i] - 10]} { + pass "current thread stepped locked" + } else { + fail "current thread stepped locked (wrong amount)" + } + } else { + fail "other thread $i didn't run (stepping) (ran)" + } + } +} + +return 0