This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFA/MI testsuite] Add pthreads tests
Keith Seitz writes:
> Hi,
>
> This is a first stab at some pthreads tests for MI. It mainly checks to
> see that the MI thread commands and the console agree about threads
> (gdb/669), but it also checks the syntax of MI thread commands and the
> like. It will add several new failures to the testsuite, since there are
> bugs! RFAs and RFCs on those to follow once these tests are committed.
>
> The pthreads.c file was largely stolen from
> testsuite/gdb.thread/pthreads.c but modified to demonstrate gdb/669.
>
I wonder if we should name the file gdb669.exp.
OK otherwise.
Elena
> Keith
>
> ChangeLog
> 2002-09-10 Keith Seitz <keiths@redhat.com>
>
> * configure.in: Add config header.
> Check for pthread.h.
> * configure: Regenerate.
> * config.in: New file.
> * mi-pthreads.exp: New file to test thread functionality.
> * pthreads.c: New file.
>
> Patch
> Index: testsuite/gdb.mi/config.in
> ===================================================================
> RCS file: testsuite/gdb.mi/config.in
> diff -N testsuite/gdb.mi/config.in
> *** testsuite/gdb.mi/config.in 1 Jan 1970 00:00:00 -0000
> --- testsuite/gdb.mi/config.in 10 Sep 2002 23:12:35 -0000
> ***************
> *** 0 ****
> --- 1,4 ----
> + /* config.h.in. Generated automatically from configure.in by autoheader. */
> +
> + /* Define if you have the <pthread.h> header file. */
> + #undef HAVE_PTHREAD_H
> Index: testsuite/gdb.mi/configure.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/testsuite/gdb.mi/configure.in,v
> retrieving revision 1.1
> diff -p -r1.1 configure.in
> *** testsuite/gdb.mi/configure.in 23 Feb 2000 00:25:43 -0000 1.1
> --- testsuite/gdb.mi/configure.in 10 Sep 2002 23:12:35 -0000
> *************** dnl any existing configure script.
> *** 6,15 ****
> --- 6,19 ----
>
> AC_PREREQ(2.5)
> AC_INIT(mi-basics.exp)
> + AC_CONFIG_HEADER(config.h:config.in)
>
> CC=${CC-cc}
> AC_SUBST(CC)
> AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../../..)
> AC_CANONICAL_SYSTEM
> +
> + # Check for pthread.h
> + AC_CHECK_HEADERS(pthread.h)
>
> AC_OUTPUT(Makefile)
> Index: testsuite/gdb.mi/mi-pthreads.exp
> ===================================================================
> RCS file: testsuite/gdb.mi/mi-pthreads.exp
> diff -N testsuite/gdb.mi/mi-pthreads.exp
> *** testsuite/gdb.mi/mi-pthreads.exp 1 Jan 1970 00:00:00 -0000
> --- testsuite/gdb.mi/mi-pthreads.exp 10 Sep 2002 23:12:35 -0000
> ***************
> *** 0 ****
> --- 1,219 ----
> + # Copyright 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 tests MI thread commands.
> + # Specifically, we are testing the MI command set and the console (in MI)
> + # command set ("interpreter-exec") and that the commands that are executed
> + # via these command pathways are properly executed. Console commands
> + # executed via MI should use MI output wrappers, MI event handlers, etc.
> +
> + # This only works with native configurations
> + if {![isnative]} {
> + return
> + }
> +
> + load_lib mi-support.exp
> + set MIFLAGS "-i=mi"
> +
> + gdb_exit
> + if {[mi_gdb_start]} {
> + continue
> + }
> +
> + proc get_mi_thread_list {name} {
> + global expect_out
> +
> + # MI will return a list of thread ids:
> + #
> + # -thread-list-ids
> + # ^done,thread-ids=[thread-id="1",thread-id="2",...],number-of-threads="N"
> + # (gdb)
> + mi_gdb_test "-thread-list-ids" \
> + {\^done,thread-ids={(thread-id="[0-9]+"(,)?)+},number-of-threads="[0-9]+"} \
> + "-thread_list_ids ($name)"
> +
> + set thread_list {}
> + if {![regexp {thread-ids=\{(thread-id="[0-9]+"(,)?)*\}} $expect_out(buffer) threads]} {
> + fail "finding threads in MI output ($name)"
> + } else {
> + pass "finding threads in MI output ($name)"
> +
> + # Make list of console threads
> + set start [expr {[string first \{ $threads] + 1}]
> + set end [expr {[string first \} $threads] - 1}]
> + set threads [string range $threads $start $end]
> + foreach thread [split $threads ,] {
> + if {[scan $thread {thread-id="%d"} num]} {
> + lappend thread_list $num
> + }
> + }
> + }
> +
> + return $thread_list
> + }
> +
> + # Check that MI and the console know of the same threads.
> + # Appends NAME to all test names.
> + proc check_mi_and_console_threads {name} {
> + global expect_out
> +
> + mi_gdb_test "-thread-list-ids" \
> + {\^done,thread-ids={(thread-id="[0-9]+"(,)*)+},number-of-threads="[0-9]+"} \
> + "-thread-list-ids ($name)"
> + set mi_output $expect_out(buffer)
> +
> + # GDB will return a list of thread ids and some more info:
> + #
> + # (gdb)
> + # -interpreter-exec console "info threads"
> + # ~" 4 Thread 2051 (LWP 7734) 0x401166b1 in __libc_nanosleep () at __libc_nanosleep:-1"
> + # ~" 3 Thread 1026 (LWP 7733) () at __libc_nanosleep:-1"
> + # ~" 2 Thread 2049 (LWP 7732) 0x401411f8 in __poll (fds=0x804bb24, nfds=1, timeout=2000) at ../sysdeps/unix/sysv/linux/poll.c:63"
> + # ~"* 1 Thread 1024 (LWP 7731) main (argc=1, argv=0xbfffdd94) at ../../../src/gdb/testsuite/gdb.mi/pthreads.c:160"
> + # FIXME: kseitz/2002-09-05: Don't use the hack-cli method.
> + mi_gdb_test "info threads" \
> + {.*(~".*"[\r\n]*)+.*} \
> + "info threads ($name)"
> + set console_output $expect_out(buffer)
> +
> + # Make a list of all known threads to console (gdb's thread IDs)
> + set console_thread_list {}
> + foreach line [split $console_output \n] {
> + if {[string index $line 0] == "~"} {
> + # This is a line from the console; trim off "~", " ", "*", and "\""
> + set line [string trim $line ~\ \"\*]
> + if {[scan $line "%d" id] == 1} {
> + lappend console_thread_list $id
> + }
> + }
> + }
> +
> + # Now find the result string from MI
> + set mi_result ""
> + foreach line [split $mi_output \n] {
> + if {[string range $line 0 4] == "^done"} {
> + set mi_result $line
> + }
> + }
> + if {$mi_result == ""} {
> + fail "finding MI result string ($name)"
> + } else {
> + pass "finding MI result string ($name)"
> + }
> +
> + # Finally, extract the thread ids and compare them to the console
> + set num_mi_threads_str ""
> + if {![regexp {number-of-threads="[0-9]+"} $mi_result num_mi_threads_str]} {
> + fail "finding number of threads in MI output ($name)"
> + } else {
> + pass "finding number of threads in MI output ($name)"
> +
> + # Extract the number of threads from the MI result
> + if {![scan $num_mi_threads_str {number-of-threads="%d"} num_mi_threads]} {
> + fail "got number of threads from MI ($name)"
> + } else {
> + pass "got number of threads from MI ($name)"
> +
> + # Check if MI and console have same number of threads
> + if {$num_mi_threads != [llength $console_thread_list]} {
> + fail "console and MI have same number of threads ($name)"
> + } else {
> + pass "console and MI have same number of threads ($name)"
> +
> + # Get MI thread list
> + set mi_thread_list [get_mi_thread_list $name]
> +
> + # Check if MI and console have the same threads
> + set fails 0
> + foreach ct [lsort $console_thread_list] mt [lsort $mi_thread_list] {
> + if {$ct != $mt} {
> + incr fails
> + }
> + }
> + if {$fails > 0} {
> + fail "MI and console have same threads ($name)"
> +
> + # Send a list of failures to the log
> + send_log "Console has thread ids: $console_thread_list\n"
> + send_log "MI has thread ids: $mi_thread_list\n"
> + } else {
> + pass "MI and console have same threads ($name)"
> + }
> + }
> + }
> + }
> + }
> +
> + # This procedure checks for the bug gdb/669, where the console
> + # command "info threads" and the MI command "-thread-list-ids"
> + # return different threads in the system.
> + proc check_for_gdb669_bug {} {
> + mi_run_to_main
> + check_mi_and_console_threads "at main"
> +
> + for {set i 0} {$i < 4} {incr i} {
> + mi_next "next, try $i"
> + check_mi_and_console_threads "try $i"
> + }
> + }
> +
> + # This procedure tests the various thread commands in MI.
> + proc check_mi_thread_command_set {} {
> +
> + mi_runto done_making_threads
> +
> + set thread_list [get_mi_thread_list "in check_mi_thread_command_set"]
> +
> + mi_gdb_test "-thread-select" \
> + {\^error,msg="mi_cmd_thread_select: USAGE: threadnum."} \
> + "check_mi_thread_command_set: -thread-select"
> +
> + mi_gdb_test "-thread-select 123456789" \
> + {\^error,msg="Thread ID 123456789 not known\."} \
> + "check_mi_thread_command_set: -thread-select 123456789"
> +
> + foreach thread $thread_list {
> + mi_gdb_test "-thread-select $thread" \
> + "\\^done,new-thread-id=\"$thread\",frame={.*},line=\"(-)?\[0-9\]+\",file=\".*\"" \
> + "check_mi_thread_command_set: -thread-select $thread"
> + }
> + }
> +
> + #
> + # Start here
> + #
> + set testfile "pthreads"
> + set srcfile "$testfile.c"
> + set binfile "$objdir/$subdir/$testfile"
> +
> + set options [list debug incdir=$subdir]
> + if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" $binfile executable $options]
> + != "" } {
> + gdb_suppress_entire_file \
> + "Testcase compile failed, so all tests in this file will automatically fail."
> + }
> +
> + mi_gdb_reinitialize_dir $srcdir/$subdir
> + mi_gdb_load $binfile
> +
> + check_mi_thread_command_set
> + check_for_gdb669_bug
> +
> + mi_gdb_exit
> +
> Index: testsuite/gdb.mi/pthreads.c
> ===================================================================
> RCS file: testsuite/gdb.mi/pthreads.c
> diff -N testsuite/gdb.mi/pthreads.c
> *** testsuite/gdb.mi/pthreads.c 1 Jan 1970 00:00:00 -0000
> --- testsuite/gdb.mi/pthreads.c 10 Sep 2002 23:12:35 -0000
> ***************
> *** 0 ****
> --- 1,80 ----
> + #include <stdio.h>
> +
> + #include "config.h"
> +
> + #ifndef HAVE_PTHREAD_H
> +
> + /* Don't even try to compile. In fact, cause a syntax error that we can
> + look for as a compiler error message and know that we have no pthread
> + support. In that case we can just suppress the test completely. */
> +
> + #error "no posix threads support"
> +
> + #else
> +
> + /* OK. We have the right header. If we try to compile this and fail, then
> + there is something wrong and the user should know about it so the testsuite
> + should issue an ERROR result.. */
> +
> + #ifdef __linux__
> + #define _MIT_POSIX_THREADS 1 /* GNU/Linux (or at least RedHat 4.0)
> + needs this */
> + #endif
> +
> + #include <pthread.h>
> +
> + /* Under OSF 2.0 & 3.0 and HPUX 10, the second arg of pthread_create
> + is prototyped to be just a "pthread_attr_t", while under Solaris it
> + is a "pthread_attr_t *". Arg! */
> +
> + #if defined (__osf__) || defined (__hpux__)
> + #define PTHREAD_CREATE_ARG2(arg) arg
> + #define PTHREAD_CREATE_NULL_ARG2 null_attr
> + static pthread_attr_t null_attr;
> + #else
> + #define PTHREAD_CREATE_ARG2(arg) &arg
> + #define PTHREAD_CREATE_NULL_ARG2 NULL
> + #endif
> +
> + void *
> + routine (void *arg)
> + {
> + sleep (9);
> + printf ("hello thread\n");
> + }
> +
> + /* Marker function for the testsuite */
> + void
> + done_making_threads (void)
> + {
> + /* Nothing */
> + };
> +
> + void
> + create_thread (void)
> + {
> + pthread_t tid;
> +
> + if (pthread_create (&tid, PTHREAD_CREATE_NULL_ARG2, routine, (void *) 0xfeedface))
> + {
> + perror ("pthread_create 1");
> + exit (1);
> + }
> + }
> +
> + int
> + main (int argc, char *argv[])
> + {
> + int i;
> +
> + /* Create a few threads */
> + for (i = 0; i < 5; i++)
> + create_thread ();
> + done_making_threads ();
> +
> + printf ("hello\n");
> + printf ("hello\n");
> + return 0;
> + }
> +
> + #endif /* ifndef HAVE_PTHREAD_H */