diff options
| -rw-r--r-- | ChangeLog | 21 | ||||
| -rw-r--r-- | condvar.c | 133 | ||||
| -rwxr-xr-x | configure | 202 | ||||
| -rw-r--r-- | configure.in | 7 | ||||
| -rw-r--r-- | rwlock.c | 2 | ||||
| -rw-r--r-- | tests/ChangeLog | 7 | ||||
| -rw-r--r-- | tests/Makefile | 4 | ||||
| -rw-r--r-- | tests/condvar7.c | 226 | ||||
| -rw-r--r-- | tests/condvar8.c | 226 | ||||
| -rw-r--r-- | tests/condvar9.c | 231 | ||||
| -rw-r--r-- | tests/runall.bat | 82 | ||||
| -rw-r--r-- | tests/runtest.bat | 25 | 
12 files changed, 960 insertions, 206 deletions
| @@ -1,3 +1,24 @@ +1999-10-17  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* rwlock.c (pthread_rwlock_destroy): Add cast to remove compile +	warning. + +	* condvar.c (pthread_cond_broadcast): Only release semaphores +	if there are waiting threads. + +1999-10-15  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* condvar.c (cond_wait_cleanup): New static cleanup handler for +	cond_timedwait; +	(cond_timedwait): pthread_cleanup_push args changed; +	canceling a thread while it's in pthread_cond_wait +	will now decrement the waiters count and cleanup if it's the +	last waiter. +	- Lorin Hochstein <lmh@xiphos.ca> and  +	  Peter Slacik <Peter.Slacik@tatramed.sk>; +	the last waiter will now reset the CV's wasBroadcast flag +	- Graham Dumpleton <Graham.Dumpleton@ra.pad.otc.telstra.com.au>. +  Thu Sep 16 1999  Ross Johnson  <rpj@swan.canberra.edu.au>  	* rwlock.c (pthread_rwlock_destroy): Add serialisation. @@ -522,6 +522,68 @@ pthread_cond_destroy (pthread_cond_t * cond)    return (result);  } +/* + * Arguments for cond_wait_cleanup, since we can only pass a + * single void * to it. + */ +typedef struct { +  pthread_mutex_t * mutexPtr; +  pthread_cond_t cv; +  int * resultPtr; +} cond_wait_cleanup_args_t; + +static void +cond_wait_cleanup(void * args) +{ +  cond_wait_cleanup_args_t * cleanup_args = (cond_wait_cleanup_args_t *) args; +  pthread_mutex_t * mutexPtr = cleanup_args->mutexPtr; +  pthread_cond_t cv = cleanup_args->cv; +  int * resultPtr = cleanup_args->resultPtr; +  int lock_result; +  int lastWaiter; + +  if ((lock_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) +    { +      /* +       * The waiter is responsible for decrementing +       * its count, protected by an internal mutex. +       */ + +      cv->waiters--; + +      lastWaiter = cv->wasBroadcast && (cv->waiters == 0); + +      if (lastWaiter) +        { +          cv->wasBroadcast = FALSE; +        } + +      lock_result = pthread_mutex_unlock (&(cv->waitersLock)); +    } + +  if ((*resultPtr == 0 || *resultPtr == ETIMEDOUT) && lock_result == 0) +    { +      if (lastWaiter) +        { +          /* +           * If we are the last waiter on this broadcast +           * let the thread doing the broadcast proceed +           */ +          if (!SetEvent (cv->waitersDone)) +            { +              *resultPtr = EINVAL; +            } +        } +    } + +  /* +   * We must always regain the external mutex, even when +   * errors occur, because that's the guarantee that we give +   * to our callers +   */ +  (void) pthread_mutex_lock (mutexPtr); +} +  static int  cond_timedwait (pthread_cond_t * cond,   		pthread_mutex_t * mutex, @@ -531,6 +593,7 @@ cond_timedwait (pthread_cond_t * cond,    int internal_result = 0;    int lastWaiter = FALSE;    pthread_cond_t cv; +  cond_wait_cleanup_args_t cleanup_args;    if (cond == NULL || *cond == NULL)      { @@ -579,6 +642,12 @@ cond_timedwait (pthread_cond_t * cond,     * call to sem_wait since that will deadlock other calls     * to pthread_cond_signal     */ +  cleanup_args.mutexPtr = mutex; +  cleanup_args.cv = cv; +  cleanup_args.resultPtr = &result; + +  pthread_cleanup_push (cond_wait_cleanup, (void *) &cleanup_args); +    if ((result = pthread_mutex_unlock (mutex)) == 0)      {        /* @@ -588,59 +657,26 @@ cond_timedwait (pthread_cond_t * cond,         *              timeout         *         * Note:  -       *      _pthread_sem_timedwait is a cancellation point, +       *      _pthread_sem_timedwait is a cancelation point,         *      hence providing the -       *      mechanism for making pthread_cond_wait a cancellation +       *      mechanism for making pthread_cond_wait a cancelation         *      point. We use the cleanup mechanism to ensure we -       *      re-lock the mutex if we are cancelled. +       *      re-lock the mutex and decrement the waiters count +       *      if we are canceled.         */ -      pthread_cleanup_push (pthread_mutex_lock, mutex); -        if (_pthread_sem_timedwait (&(cv->sema), abstime) == -1)  	{  	  result = errno;  	} - -      pthread_cleanup_pop (0); -    } - -  if ((internal_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) -    { -      /* -       * The waiter is responsible for decrementing -       * its count, protected by an internal mutex. -       */ - -      cv->waiters--; - -      lastWaiter = cv->wasBroadcast && (cv->waiters == 0); - -      internal_result = pthread_mutex_unlock (&(cv->waitersLock));      } -  if ((result == 0 || result == ETIMEDOUT) && internal_result == 0) -    { -      if (lastWaiter) -        { -          /* -           * If we are the last waiter on this broadcast -           * let the thread doing the broadcast proceed -           */ -          if (!SetEvent (cv->waitersDone)) -            { -              result = EINVAL; -            } -        } -    } +  pthread_cleanup_pop (1);    /* -   * We must always regain the external mutex, even when -   * errors occur, because that's the guarantee that we give -   * to our callers +   * "result" can be modified by the cleanup handler. +   * Specifically, if we are the last waiting thread and failed +   * to notify the broadcast thread to proceed.     */ -  (void) pthread_mutex_lock (mutex); - -    return (result);  }                               /* cond_timedwait */ @@ -905,12 +941,15 @@ pthread_cond_broadcast (pthread_cond_t * cond)    cv->wasBroadcast = TRUE;    wereWaiters = (cv->waiters > 0); -  /* -   * Wake up all waiters -   */ -  result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) -	    ? 0 -	    : EINVAL); +  if (wereWaiters) +    { +      /* +       * Wake up all waiters +       */ +      result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) +	        ? 0 +	        : EINVAL ); +    }    (void) pthread_mutex_unlock(&(cv->waitersLock)); @@ -1,7 +1,7 @@  #! /bin/sh  # Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.12.2  +# Generated automatically using autoconf version 2.13   # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.  #  # This configure script is free software; the Free Software Foundation @@ -333,7 +333,7 @@ EOF      verbose=yes ;;    -version | --version | --versio | --versi | --vers) -    echo "configure generated by autoconf version 2.12.2" +    echo "configure generated by autoconf version 2.13"      exit 0 ;;    -with-* | --with-*) @@ -579,7 +579,8 @@ else    ac_cv_prog_CC="$CC" # Let the user override the test.  else    IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":" -  for ac_dir in $PATH; do +  ac_dummy="$PATH" +  for ac_dir in $ac_dummy; do      test -z "$ac_dir" && ac_dir=.      if test -f $ac_dir/$ac_word; then        ac_cv_prog_CC="gcc" @@ -600,7 +601,7 @@ if test -z "$CC"; then    # Extract the first word of "cc", so it can be a program name with args.  set dummy cc; ac_word=$2  echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:604: checking for $ac_word" >&5 +echo "configure:605: checking for $ac_word" >&5  if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else @@ -609,7 +610,8 @@ else  else    IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"    ac_prog_rejected=no -  for ac_dir in $PATH; do +  ac_dummy="$PATH" +  for ac_dir in $ac_dummy; do      test -z "$ac_dir" && ac_dir=.      if test -f $ac_dir/$ac_word; then        if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then @@ -650,7 +652,7 @@ fi        # Extract the first word of "cl", so it can be a program name with args.  set dummy cl; ac_word=$2  echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:654: checking for $ac_word" >&5 +echo "configure:656: checking for $ac_word" >&5  if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else @@ -658,7 +660,8 @@ else    ac_cv_prog_CC="$CC" # Let the user override the test.  else    IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":" -  for ac_dir in $PATH; do +  ac_dummy="$PATH" +  for ac_dir in $ac_dummy; do      test -z "$ac_dir" && ac_dir=.      if test -f $ac_dir/$ac_word; then        ac_cv_prog_CC="cl" @@ -681,7 +684,7 @@ fi  fi  echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:685: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:688: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5  ac_ext=c  # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -690,12 +693,14 @@ ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'  ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'  cross_compiling=$ac_cv_prog_cc_cross -cat > conftest.$ac_ext <<EOF -#line 695 "configure" +cat > conftest.$ac_ext << EOF + +#line 699 "configure"  #include "confdefs.h" +  main(){return(0);}  EOF -if { (eval echo configure:699: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:704: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then    ac_cv_prog_cc_works=yes    # If we can't run a trivial program, we are probably using a cross compiler.    if (./conftest; exit) 2>/dev/null; then @@ -709,18 +714,24 @@ else    ac_cv_prog_cc_works=no  fi  rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross  echo "$ac_t""$ac_cv_prog_cc_works" 1>&6  if test $ac_cv_prog_cc_works = no; then    { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }  fi  echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:719: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:730: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5  echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6  cross_compiling=$ac_cv_prog_cc_cross  echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:724: checking whether we are using GNU C" >&5 +echo "configure:735: checking whether we are using GNU C" >&5  if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else @@ -729,7 +740,7 @@ else    yes;  #endif  EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:733: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:744: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then    ac_cv_prog_gcc=yes  else    ac_cv_prog_gcc=no @@ -748,7 +759,7 @@ ac_test_CFLAGS="${CFLAGS+set}"  ac_save_CFLAGS="$CFLAGS"  CFLAGS=  echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:752: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:763: checking whether ${CC-cc} accepts -g" >&5  if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else @@ -779,8 +790,9 @@ else    fi  fi +  echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:784: checking how to run the C preprocessor" >&5 +echo "configure:796: checking how to run the C preprocessor" >&5  # On Suns, sometimes $CPP names a directory.  if test -n "$CPP" && test -d "$CPP"; then    CPP= @@ -795,13 +807,13 @@ else    # On the NeXT, cc -E runs the code through the compiler's parser,    # not just through cpp.    cat > conftest.$ac_ext <<EOF -#line 799 "configure" +#line 811 "configure"  #include "confdefs.h"  #include <assert.h>  Syntax Error  EOF  ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:805: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:817: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }  ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`  if test -z "$ac_err"; then    : @@ -812,13 +824,13 @@ else    rm -rf conftest*    CPP="${CC-cc} -E -traditional-cpp"    cat > conftest.$ac_ext <<EOF -#line 816 "configure" +#line 828 "configure"  #include "confdefs.h"  #include <assert.h>  Syntax Error  EOF  ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:822: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:834: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }  ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`  if test -z "$ac_err"; then    : @@ -829,13 +841,13 @@ else    rm -rf conftest*    CPP="${CC-cc} -nologo -E"    cat > conftest.$ac_ext <<EOF -#line 833 "configure" +#line 845 "configure"  #include "confdefs.h"  #include <assert.h>  Syntax Error  EOF  ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:839: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }  ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`  if test -z "$ac_err"; then    : @@ -859,21 +871,19 @@ else  fi  echo "$ac_t""$CPP" 1>&6 -for ac_hdr in signal.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:867: checking for $ac_hdr" >&5 +ac_safe=`echo "windows.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for windows.h""... $ac_c" 1>&6 +echo "configure:877: checking for windows.h" >&5  if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else    cat > conftest.$ac_ext <<EOF -#line 872 "configure" +#line 882 "configure"  #include "confdefs.h" -#include <$ac_hdr> +#include <windows.h>  EOF -ac_try="$ac_cpp conftest.$ac_ext >a.out 2>conftest.out" -{ (eval echo configure:877: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:887: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }  ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`  if test -z "$ac_err"; then    rm -rf conftest* @@ -889,134 +899,83 @@ rm -f conftest*  fi  if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then    echo "$ac_t""yes" 1>&6 -    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` -  cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - signal_h=yes +  :  else    echo "$ac_t""no" 1>&6 +{ echo "configure: error: Target system must be Win32" 1>&2; exit 1; }  fi -done -if test x$signal_h = xyes -then -  echo $ac_n "checking for sigset_t""... $ac_c" 1>&6 -echo "configure:906: checking for sigset_t" >&5 -if eval "test \"`echo '$''{'p32_cv_sigset_t'+set}'`\" = set"; then + +ac_safe=`echo "signal.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for signal.h""... $ac_c" 1>&6 +echo "configure:912: checking for signal.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else    cat > conftest.$ac_ext <<EOF -#line 911 "configure" +#line 917 "configure"  #include "confdefs.h"  #include <signal.h> -int main() { -sigset_t x; -; return 0; }  EOF -if { (eval echo configure:918: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:922: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then    rm -rf conftest* -  p32_cv_sigset_t=yes +  eval "ac_cv_header_$ac_safe=yes"  else +  echo "$ac_err" >&5    echo "configure: failed program was:" >&5    cat conftest.$ac_ext >&5    rm -rf conftest* -  p32_cv_sigset_t=no +  eval "ac_cv_header_$ac_safe=no"  fi  rm -f conftest*  fi - -echo "$ac_t""$p32_cv_sigset_t" 1>&6 - -  if test x$p32_cv_sigset_t = xyes ; then -    cat >> confdefs.h <<\EOF -#define HAVE_SIGSET_T 1 -EOF - -  fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then +  echo "$ac_t""yes" 1>&6 +  signal_h=yes +else +  echo "$ac_t""no" 1>&6  fi -echo $ac_n "checking for _stdcall keyword""... $ac_c" 1>&6 -echo "configure:940: checking for _stdcall keyword" >&5 -if eval "test \"`echo '$''{'p32_cv_stdcall'+set}'`\" = set"; then + +if test x$signal_h = xyes +then +  echo $ac_n "checking for sigset_t""... $ac_c" 1>&6 +echo "configure:946: checking for sigset_t" >&5 +if eval "test \"`echo '$''{'p32_cv_sigset_t'+set}'`\" = set"; then    echo $ac_n "(cached) $ac_c" 1>&6  else    cat > conftest.$ac_ext <<EOF -#line 945 "configure" +#line 951 "configure"  #include "confdefs.h" - +#include <signal.h>  int main() { -int __stdcall foo(); +sigset_t x;  ; return 0; }  EOF -if { (eval echo configure:952: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:958: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then    rm -rf conftest* -  p32_cv_stdcall=yes +  p32_cv_sigset_t=yes  else    echo "configure: failed program was:" >&5    cat conftest.$ac_ext >&5    rm -rf conftest* -  p32_cv_stdcall=no +  p32_cv_sigset_t=no  fi  rm -f conftest*  fi -echo "$ac_t""$p32_cv_stdcall" 1>&6 - -if test x$p32_cv_stdcall = xyes ; then -  cat >> confdefs.h <<\EOF -#define STDCALL __stdcall -EOF +echo "$ac_t""$p32_cv_sigset_t" 1>&6 -else -  cat >> confdefs.h <<\EOF -#ifndef STDCALL -#define STDCALL  -#endif +  if test x$p32_cv_sigset_t = xyes ; then +    cat >> confdefs.h <<\EOF +#define HAVE_SIGSET_T 1  EOF +  fi  fi -for ac_hdr in windows.h -do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:982: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then -  echo $ac_n "(cached) $ac_c" 1>&6 -else -  cat > conftest.$ac_ext <<EOF -#line 987 "configure" -#include <$ac_hdr> -#include "confdefs.h" -EOF -ac_try="$ac_cpp conftest.$ac_ext >a.out 2>conftest.out" -{ (eval echo configure:992: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then -  rm -rf conftest* -  eval "ac_cv_header_$ac_safe=yes" -else -  echo "$ac_err" >&5 -  echo "configure: failed program was:" >&5 -  cat conftest.$ac_ext >&5 -  rm -rf conftest* -  eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then -  echo "$ac_t""yes" 1>&6 -    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` -  cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF -  -else -  echo "$ac_t""no" 1>&6 -echo "configure: warning: Target system must be Win32" 1>&2 -fi -done -  trap '' 1 2 15  cat > confcache <<\EOF  # This file is a shell script that caches the results of configure @@ -1040,7 +999,7 @@ EOF  # Ultrix sh set writes to stderr and can't be redirected directly,  # and sets the high bit in the cache file unless we assign to the vars.  (set) 2>&1 | -  case `(ac_space=' '; set) 2>&1 | grep ac_space` in +  case `(ac_space=' '; set | grep ac_space) 2>&1` in    *ac_space=\ *)      # `set' does not quote correctly, so add quotes (double-quote substitution      # turns \\\\ into \\, and sed turns \\ into \). @@ -1107,7 +1066,7 @@ do      echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"      exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;    -version | --version | --versio | --versi | --vers | --ver | --ve | --v) -    echo "$CONFIG_STATUS generated by autoconf version 2.12.2" +    echo "$CONFIG_STATUS generated by autoconf version 2.13"      exit 0 ;;    -help | --help | --hel | --he | --h)      echo "\$ac_cs_usage"; exit 0 ;; @@ -1130,6 +1089,7 @@ s%@SHELL@%$SHELL%g  s%@CFLAGS@%$CFLAGS%g  s%@CPPFLAGS@%$CPPFLAGS%g  s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g  s%@DEFS@%$DEFS%g  s%@LDFLAGS@%$LDFLAGS%g  s%@LIBS@%$LIBS%g diff --git a/configure.in b/configure.in index 0896edb..5c4dfac 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,11 @@ AC_INIT(pthread.h)  AC_CANONICAL_HOST  AC_CONFIG_HEADER(config.h)  AC_PROG_CC -AC_CHECK_HEADERS([signal.h],signal_h=yes,) + +dnl Abort here if there is no windows.h +AC_CHECK_HEADER([windows.h],,AC_MSG_ERROR([Target system must be Win32])) + +AC_CHECK_HEADER([signal.h],signal_h=yes,)  if test x$signal_h = xyes  then    AC_CACHE_CHECK([for sigset_t], p32_cv_sigset_t, @@ -16,5 +20,4 @@ then    fi  fi -AC_CHECK_HEADERS(windows.h,,AC_MSG_WARN([Target system must be Win32]))  AC_OUTPUT(Makefile) @@ -182,7 +182,7 @@ pthread_rwlock_destroy(pthread_rwlock_t *rwlock)            }          else            { -            rw->rw_magic = NULL; +            rw->rw_magic = (int) NULL;              (void) pthread_mutex_unlock(&(rw->rw_lock));              (void) pthread_cond_destroy(&(rw->rw_condreaders));              (void) pthread_cond_destroy(&(rw->rw_condwriters)); diff --git a/tests/ChangeLog b/tests/ChangeLog index 2283e3a..ee69577 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,10 @@ +Oct 14 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* condvar7.c: New. Test broadcast after waiting thread is canceled. +	* condvar8.c: New. Test multiple broadcasts. +	* condvar9.c: New. Test multiple broadcasts with thread +	cancelation. +	  Sep 16 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* rwlock6.c: New test. diff --git a/tests/Makefile b/tests/Makefile index e2c298d..0263769 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -40,7 +40,7 @@ TESTS	= mutex1 condvar1 condvar2 exit1 create1 equal1 \  	  exit2 exit3 \  	  join1 join2 mutex2 mutex3 \  	  count1 once1 tsd1 self1 self2 eyal1 \ -	  condvar3 condvar4 condvar5 condvar6 \ +	  condvar3 condvar4 condvar5 condvar6 condvar7 condvar8 \  	  errno1 \  	  rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 @@ -71,6 +71,8 @@ condvar3.pass: create1.pass  condvar4.pass: create1.pass  condvar5.pass: condvar4.pass  condvar6.pass: condvar5.pass +condvar7.pass: condvar6.pass +condvar8.pass: condvar6.pass  errno1.pass: mutex3.pass  rwlock1.pass: condvar6.pass  rwlock2.pass: rwlock1.pass diff --git a/tests/condvar7.c b/tests/condvar7.c new file mode 100644 index 0000000..d81dd78 --- /dev/null +++ b/tests/condvar7.c @@ -0,0 +1,226 @@ +/* + * File: condvar7.c + * + * Test Synopsis: + * - Test pthread_cond_broadcast with thread cancelation. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * -  + * + * Features Tested: + * -  + * + * Cases Tested: + * -  + * + * Description: + * - Test broadcast with NUMTHREADS (=5) waiting CVs, one is canceled while waiting. + * + * Environment: + * -  + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * -  + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" +#include <sys/timeb.h> + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { +  NUMTHREADS = 5 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ { +  int threadnum; +  int started; +  /* Add more per-thread state variables here */ +}; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ { +  pthread_cond_t notbusy; +  pthread_mutex_t lock; +  int shared; +}; + +static cvthing_t cvthing = { +  PTHREAD_COND_INITIALIZER, +  PTHREAD_MUTEX_INITIALIZER, +  0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = { 0, 0 }; + +static int awoken; + +void * +mythread(void * arg) +{ +  bag_t * bag = (bag_t *) arg; + +  assert(bag == &threadbag[bag->threadnum]); +  assert(bag->started == 0); +  bag->started = 1; + +  /* Wait for the start gun */ +  assert(pthread_mutex_lock(&start_flag) == 0); +  assert(pthread_mutex_unlock(&start_flag) == 0); + +  assert(pthread_mutex_lock(&cvthing.lock) == 0); + +  pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); + +  while (! cvthing.shared > 0) +    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + +  pthread_cleanup_pop(0); + +  assert(cvthing.shared > 0); + +  awoken++; + +  assert(pthread_mutex_unlock(&cvthing.lock) == 0); + +  return 0; +} + +int +main() +{ +  int failed = 0; +  int i; +  pthread_t t[NUMTHREADS + 1]; + +#if defined(__MINGW32__) +  struct timeb currSysTime; +#else +  struct _timeb currSysTime; +#endif +  const DWORD NANOSEC_PER_MILLISEC = 1000000; + +  cvthing.shared = 0; + +  assert((t[0] = pthread_self()) != NULL); + +  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + +  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + +  assert(pthread_mutex_lock(&start_flag) == 0); + +  _ftime(&currSysTime); + +  abstime.tv_sec = currSysTime.time; +  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; + +  abstime.tv_sec += 5; + +  assert((t[0] = pthread_self()) != NULL); + +  awoken = 0; + +  for (i = 1; i <= NUMTHREADS; i++) +    { +      threadbag[i].started = 0; +      threadbag[i].threadnum = i; +      assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); +    } + +  /* +   * Code to control or munipulate child threads should probably go here. +   */ + +  assert(pthread_mutex_unlock(&start_flag) == 0); + +  /* +   * Give threads time to start. +   */ +  Sleep(2000); + +  assert(pthread_mutex_lock(&cvthing.lock) == 0); + +  cvthing.shared++; + +  assert(pthread_mutex_unlock(&cvthing.lock) == 0); + +  /* +   * Cancel one of the threads. +   */ +  assert(pthread_cancel(t[3]) == 0); +  Sleep(500); + +  /* +   * Signal all remaining waiting threads. +   */ +  assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + +  /* +   * Give threads time to complete. +   */ +  Sleep(2000); + +  /*  +   * Cleanup the CV. +   */ +   +  assert(pthread_mutex_destroy(&cvthing.lock) == 0); + +  assert(cvthing.lock == NULL); + +  assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + +  assert(cvthing.notbusy == NULL); + +  /* +   * Standard check that all threads started. +   */ +  for (i = 1; i <= NUMTHREADS; i++) +    {  +      failed = !threadbag[i].started; + +      if (failed) +	{ +	  fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); +	} +    } + +  assert(!failed); + +  /* +   * Check any results here. +   */ + +  assert(awoken == (NUMTHREADS - 1)); + +  /* +   * Success. +   */ +  return 0; +} + + diff --git a/tests/condvar8.c b/tests/condvar8.c new file mode 100644 index 0000000..65da040 --- /dev/null +++ b/tests/condvar8.c @@ -0,0 +1,226 @@ +/* + * File: condvar8.c + * + * Test Synopsis: + * - Test multiple pthread_cond_broadcasts. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * -  + * + * Features Tested: + * -  + * + * Cases Tested: + * -  + * + * Description: + * - Make NUMTHREADS threads wait on CV, broadcast signal them, and then repeat. + * + * Environment: + * -  + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * -  + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" +#include <sys/timeb.h> + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { +  NUMTHREADS = 5 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ { +  int threadnum; +  int started; +  /* Add more per-thread state variables here */ +}; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ { +  pthread_cond_t notbusy; +  pthread_mutex_t lock; +  int shared; +}; + +static cvthing_t cvthing = { +  PTHREAD_COND_INITIALIZER, +  PTHREAD_MUTEX_INITIALIZER, +  0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = { 0, 0 }; + +static int awoken; + +static void * +mythread(void * arg) +{ +  bag_t * bag = (bag_t *) arg; + +  assert(bag == &threadbag[bag->threadnum]); +  assert(bag->started == 0); +  bag->started = 1; + +  /* Wait for the start gun */ +  assert(pthread_mutex_lock(&start_flag) == 0); +  assert(pthread_mutex_unlock(&start_flag) == 0); + +  assert(pthread_mutex_lock(&cvthing.lock) == 0); + +  /* +   * pthread_cond_timedwait is a cancelation point and we +   * going to cancel one deliberately. +   */ +  pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); + +  while (! cvthing.shared > 0) +    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + +  pthread_cleanup_pop(0); + +  assert(cvthing.shared > 0); + +  awoken++; + +  assert(pthread_mutex_unlock(&cvthing.lock) == 0); + +  return 0; +} + +int +main() +{ +  int failed = 0; +  int i; +  int first, last; +  pthread_t t[NUMTHREADS + 1]; + +#if defined(__MINGW32__) +  struct timeb currSysTime; +#else +  struct _timeb currSysTime; +#endif +  const DWORD NANOSEC_PER_MILLISEC = 1000000; + +  assert((t[0] = pthread_self()) != NULL); + +  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + +  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + +  _ftime(&currSysTime); + +  abstime.tv_sec = currSysTime.time; +  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; + +  abstime.tv_sec += 5; + +  assert((t[0] = pthread_self()) != NULL); + +  awoken = 0; + +  for (first = 1, last = NUMTHREADS / 2; +       first < NUMTHREADS; +       first = last + 1, last = NUMTHREADS) +    { +      assert(pthread_mutex_lock(&start_flag) == 0); + +      for (i = first; i <= last; i++) +	{ +	  threadbag[i].started = 0; +	  threadbag[i].threadnum = i; +	  assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); +	  assert(pthread_detach(t[i]) == 0); +	} + +      /* +       * Code to control or munipulate child threads should probably go here. +       */ +      cvthing.shared = 0; + +      assert(pthread_mutex_unlock(&start_flag) == 0); + +      /* +       * Give threads time to start. +       */ +      Sleep(1000); + +      assert(pthread_mutex_lock(&cvthing.lock) == 0); + +      cvthing.shared++; + +      assert(pthread_mutex_unlock(&cvthing.lock) == 0); + +      assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + +      /* +       * Give threads time to complete. +       */ +      Sleep(1000); +    } + + +  /* +   * Standard check that all threads started. +   */ +  for (i = 1; i <= NUMTHREADS; i++) +    {  +      failed = !threadbag[i].started; + +      if (failed) +        { +          fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); +        } +    } + +  /*  +   * Cleanup the CV. +   */ +   +  assert(pthread_mutex_destroy(&cvthing.lock) == 0); + +  assert(cvthing.lock == NULL); + +  assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + +  assert(cvthing.notbusy == NULL); + +  assert(!failed); + +  /* +   * Check any results here. +   */ + +  assert(awoken == NUMTHREADS); + +  /* +   * Success. +   */ +  return 0; +} diff --git a/tests/condvar9.c b/tests/condvar9.c new file mode 100644 index 0000000..49a8cab --- /dev/null +++ b/tests/condvar9.c @@ -0,0 +1,231 @@ +/* + * File: condvar9.c + * + * Test Synopsis: + * - Test multiple pthread_cond_broadcasts with thread cancelation. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * -  + * + * Features Tested: + * -  + * + * Cases Tested: + * -  + * + * Description: + * - Make NUMTHREADS threads wait on CV, cancel one, broadcast signal them, + *   and then repeat. + * + * Environment: + * -  + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * -  + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" +#include <sys/timeb.h> + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { +  NUMTHREADS = 9 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ { +  int threadnum; +  int started; +  /* Add more per-thread state variables here */ +}; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ { +  pthread_cond_t notbusy; +  pthread_mutex_t lock; +  int shared; +}; + +static cvthing_t cvthing = { +  PTHREAD_COND_INITIALIZER, +  PTHREAD_MUTEX_INITIALIZER, +  0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = { 0, 0 }; + +static int awoken; + +static void * +mythread(void * arg) +{ +  bag_t * bag = (bag_t *) arg; + +  assert(bag == &threadbag[bag->threadnum]); +  assert(bag->started == 0); +  bag->started = 1; + +  /* Wait for the start gun */ +  assert(pthread_mutex_lock(&start_flag) == 0); +  assert(pthread_mutex_unlock(&start_flag) == 0); + +  assert(pthread_mutex_lock(&cvthing.lock) == 0); + +  /* +   * pthread_cond_timedwait is a cancelation point and we +   * going to cancel one deliberately. +   */ +  pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); + +  while (! cvthing.shared > 0) +    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + +  pthread_cleanup_pop(0); + +  assert(cvthing.shared > 0); + +  awoken++; + +  assert(pthread_mutex_unlock(&cvthing.lock) == 0); + +  return 0; +} + +int +main() +{ +  int failed = 0; +  int i; +  int first, last; +  int canceledThreads = 0; +  pthread_t t[NUMTHREADS + 1]; + +#if defined(__MINGW32__) +  struct timeb currSysTime; +#else +  struct _timeb currSysTime; +#endif +  const DWORD NANOSEC_PER_MILLISEC = 1000000; + +  assert((t[0] = pthread_self()) != NULL); + +  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + +  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + +  _ftime(&currSysTime); + +  abstime.tv_sec = currSysTime.time; +  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; + +  abstime.tv_sec += 5; + +  assert((t[0] = pthread_self()) != NULL); + +  awoken = 0; + +  for (first = 1, last = NUMTHREADS / 2; +       first < NUMTHREADS; +       first = last + 1, last = NUMTHREADS) +    { +      assert(pthread_mutex_lock(&start_flag) == 0); + +      for (i = first; i <= last; i++) +	{ +	  threadbag[i].started = 0; +	  threadbag[i].threadnum = i; +	  assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); +	  assert(pthread_detach(t[i]) == 0); +	} + +      /* +       * Code to control or munipulate child threads should probably go here. +       */ +      cvthing.shared = 0; + +      assert(pthread_mutex_unlock(&start_flag) == 0); + +      /* +       * Give threads time to start. +       */ +      Sleep(1000); + +      assert(pthread_mutex_lock(&cvthing.lock) == 0); + +      cvthing.shared++; + +      assert(pthread_mutex_unlock(&cvthing.lock) == 0); + +      assert(pthread_cancel(t[(first + last) / 2]) == 0); +      canceledThreads++; + +      assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + +      /* +       * Give threads time to complete. +       */ +      Sleep(1000); +    } + + +  /* +   * Standard check that all threads started. +   */ +  for (i = 1; i <= NUMTHREADS; i++) +    {  +      failed = !threadbag[i].started; + +      if (failed) +        { +          fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); +        } +    } + +  /*  +   * Cleanup the CV. +   */ +   +  assert(pthread_mutex_destroy(&cvthing.lock) == 0); + +  assert(cvthing.lock == NULL); + +  assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + +  assert(cvthing.notbusy == NULL); + +  assert(!failed); + +  /* +   * Check any results here. +   */ + +  assert(awoken == NUMTHREADS - canceledThreads); + +  /* +   * Success. +   */ +  return 0; +} diff --git a/tests/runall.bat b/tests/runall.bat index a1e3862..e3a927b 100644 --- a/tests/runall.bat +++ b/tests/runall.bat @@ -1,33 +1,55 @@  @echo off -if x%1==x-f echo y | erase *.pass > nul: +if NOT x%1==x-f goto noforce +if EXIST *.pass echo y | erase *.pass > nul: +if EXIST *.fail echo y | erase *.fail > nul: +if EXIST *.notrun echo y | erase *.notrun > nul: -call runtest cl mutex1 -call runtest cl mutex2 -call runtest cl exit1 -call runtest cl condvar1 -call runtest cl self1 -call runtest cl condvar2 -call runtest cl create1 -call runtest cl mutex3 -call runtest cl equal1 -call runtest cl exit2 -call runtest cl exit3 -call runtest cl join1 -call runtest cl join2 -call runtest cl count1 -call runtest cl once1 -call runtest cl tsd1 -call runtest cl self2 -call runtest cl eyal1 -call runtest cl condvar3 -call runtest cl condvar4 -call runtest cl condvar5 -call runtest cl condvar6 -call runtest cl errno1 -call runtest cl rwlock1 -call runtest cl rwlock2 -call runtest cl rwlock3 -call runtest cl rwlock4 -call runtest cl rwlock5 -call runtest cl rwlock6 +:noforce +call runtest cl mutex1 _ +call runtest cl mutex2 _ +call runtest cl exit1 _ +call runtest cl condvar1 _ +call runtest cl self1 _ +call runtest cl condvar2 condvar1 +call runtest cl create1 mutex2 +call runtest cl mutex3 create1 +call runtest cl equal1 create1 +call runtest cl exit2 create1 +call runtest cl exit3 create1 +call runtest cl join1 create1 +call runtest cl join2 create1 +call runtest cl count1 join1 +call runtest cl once1 create1 +call runtest cl tsd1 join1 +call runtest cl self2 create1 +call runtest cl eyal1 tsd1 +call runtest cl condvar3 create1 +call runtest cl condvar4 create1 +call runtest cl condvar5 condvar4 +call runtest cl condvar6 condvar5 +call runtest cl condvar7 condvar6 +call runtest cl condvar8 condvar7 +call runtest cl condvar9 condvar8 +call runtest cl errno1 mutex3 +call runtest cl rwlock1 condvar6 +call runtest cl rwlock2 rwlock1 +call runtest cl rwlock3 rwlock2 +call runtest cl rwlock4 rwlock3 +call runtest cl rwlock5 rwlock4 +call runtest cl rwlock6 rwlock5 + +if NOT EXIST *.notrun goto skip1 +echo The following tests did not run (because prerequisite didn't pass?): +for %%f in (*.notrun) do echo %%f +goto skip2 +:skip1 +echo All tests ran. +:skip2 +if NOT EXIST *.fail goto skip3 +echo The following tests failed: +for %%f in (*.fail) do echo %%f +goto skip4 +:skip3 +echo No tests failed. +:skip4 diff --git a/tests/runtest.bat b/tests/runtest.bat index 4a06505..73fae97 100644 --- a/tests/runtest.bat +++ b/tests/runtest.bat @@ -1,7 +1,11 @@  @echo off -REM Usage: runtest cl|gcc testname testarg ... +REM Usage: runtest cl|gcc testname prerequisit testarg ... +if %3==_ goto noprereq +if NOT EXIST %3.pass goto needprereq + +:noprereq  if EXIST %2.pass goto bypass  REM Make sure we start with only those files we expect to need @@ -30,11 +34,15 @@ REM erase ..\%2.%1log  echo TEST: %2 [%1]  REM Run the test case -aout.exe %3 %4 %5 %6 %7 %8 %9 +if EXIST %2.pass erase %2.pass +if EXIST %2.fail erase %2.fail +if EXIST %2.notrun erase %2.notrun +aout.exe %4 %5 %6 %7 %8 %9  set RESULT=%ERRORLEVEL% -if %RESULT% EQU 0 echo Passed [%RESULT%] > ..\%2.pass +if %RESULT% NEQ 0 echo Failed [%RESULT%] > ..\%2.fail +if %RESULT% EQU 0 echo Passed > ..\%2.pass  :cleanup @@ -43,6 +51,15 @@ cd ..  REM Clean up  if exist tmp\*.* echo y | erase tmp\*.* > nul: +if EXIST %2.fail echo Failed [%RESULT%]  if EXIST %2.pass echo Passed [%RESULT%] -:bypass
\ No newline at end of file +:bypass +goto end + +:needprereq +echo Test %2 requires %3 to pass before it can run. +echo No Prereq > ..\%2.notrun +goto end + +:end | 
