From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13103 invoked by alias); 22 Aug 2002 23:34:53 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 13096 invoked from network); 22 Aug 2002 23:34:52 -0000 Received: from unknown (HELO cygnus.com) (205.180.83.203) by sources.redhat.com with SMTP; 22 Aug 2002 23:34:52 -0000 Received: from redhat.com (reddwarf.sfbay.redhat.com [172.16.24.50]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id QAA09114; Thu, 22 Aug 2002 16:28:59 -0700 (PDT) Message-ID: <3D65751B.98E850BA@redhat.com> Date: Thu, 22 Aug 2002 16:41:00 -0000 From: Michael Snyder Organization: Red Hat, Inc. X-Accept-Language: en MIME-Version: 1.0 To: Daniel Jacobowitz CC: gdb-patches@sources.redhat.com Subject: Re: RFA (threads testsuite): More thread tests References: <20020709154033.GA7204@nevyn.them.org> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2002-08/txt/msg00738.txt.bz2 Daniel Jacobowitz wrote: > > Here's two tests I had lying around from when I developed the gdbserver > threads support. Gdbserver passes them with flying colors (if you use my > other patch which lets gdbserver run tests properly). GDB shows a couple of > problems, unpredictably (not always repeatable). > > OK to add these? Hi Joel, I understand the point of schedlock.exp, but what's the point of print-threads.exp? What is it that you're testing? Michael > > -- > Daniel Jacobowitz Carnegie Mellon University > MontaVista Software Debian GNU/Linux Developer > > 2002-07-09 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. > > --- /dev/null Wed Dec 31 19:00:00 1969 > +++ gdb.threads/print-threads.c Tue Jun 11 14:56:44 2002 > @@ -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); > +} > + > --- /dev/null Wed Dec 31 19:00:00 1969 > +++ gdb.threads/print-threads.exp Tue Jun 11 14:56:44 2002 > @@ -0,0 +1,158 @@ > +# 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). > + > +if $tracelevel then { > + strace $tracelevel > +} > + > +set prms_id 0 > +set bug_id 0 > + > +# This only works with native configurations > +if ![isnative] then { > + return > +} > + > +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 > --- /dev/null Wed Dec 31 19:00:00 1969 > +++ gdb.threads/schedlock.c Tue Jun 11 14:56:44 2002 > @@ -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); > +} > + > --- /dev/null Wed Dec 31 19:00:00 1969 > +++ gdb.threads/schedlock.exp Tue Jun 11 14:56:44 2002 > @@ -0,0 +1,374 @@ > +# 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). > + > +if $tracelevel then { > + strace $tracelevel > +} > + > +set prms_id 0 > +set bug_id 0 > + > +# This only works with native configurations > +if ![isnative] then { > + return > +} > + > +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)" > + } > + } > + > + return > + send_gdb "info threads\n" > + gdb_expect { > + -re "\\* (\[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