This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA (threads testsuite): More thread tests


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  <drow@mvista.com>
> 
>         * 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 <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <pthread.h>
> +
> +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 <drow@mvista.com>
> +# (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 <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <pthread.h>
> +
> +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 <drow@mvista.com>
> +# (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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]