summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>1999-10-16 16:24:42 +0000
committerrpj <rpj>1999-10-16 16:24:42 +0000
commit8c238590dc9ad996710abc28a1868e9f1a41ab0a (patch)
tree972e0edb16402e27c7cc3248c6273fe65bac59e7
parentcd324bb05bc5c76589c2ef7a2fcce61345100682 (diff)
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>.
-rw-r--r--ChangeLog21
-rw-r--r--condvar.c133
-rwxr-xr-xconfigure202
-rw-r--r--configure.in7
-rw-r--r--rwlock.c2
-rw-r--r--tests/ChangeLog7
-rw-r--r--tests/Makefile4
-rw-r--r--tests/condvar7.c226
-rw-r--r--tests/condvar8.c226
-rw-r--r--tests/condvar9.c231
-rw-r--r--tests/runall.bat82
-rw-r--r--tests/runtest.bat25
12 files changed, 960 insertions, 206 deletions
diff --git a/ChangeLog b/ChangeLog
index c7c83cc..c0dc818 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/condvar.c b/condvar.c
index 3f9a7df..4b41a23 100644
--- a/condvar.c
+++ b/condvar.c
@@ -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));
diff --git a/configure b/configure
index f9489a2..33b2a22 100755
--- a/configure
+++ b/configure
@@ -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)
diff --git a/rwlock.c b/rwlock.c
index d135c39..fd3f1f7 100644
--- a/rwlock.c
+++ b/rwlock.c
@@ -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