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).
> 

Can you elaborate on what these problems are and on which host you've
seen them?


> OK to add these?
> 

Michael Snyder, have you seen these?


Daniel, in the meanwhile please fix your CL entries.  
After the "New file." please briefly say what the new files are for.

Also, we need some comments in the new testfile headers saying
what the tests are testing.  So far we have to infer from the file names
;-)


Are there some lines missing in your  get_current_thread  proc?
The second part is after a return that seem orphan in there.


AFAICT the rest looks very nice.  I am really concerned with the
intermittent failures you've mentioned though.

Regards,
Fernando


> --
> 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

-- 
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9


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