summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorrpj <rpj>2005-05-06 07:27:10 +0000
committerrpj <rpj>2005-05-06 07:27:10 +0000
commit7523c7c4d75652f67cd31cb123e1268790394c8b (patch)
tree0920ebf089ccb971e0878542f85486171a541a8a /tests
parentcf42850c77554311e62d3780f6a36cbc38e5e002 (diff)
''
Diffstat (limited to 'tests')
-rw-r--r--tests/Bmakefile15
-rw-r--r--tests/GNUmakefile32
-rw-r--r--tests/Makefile76
-rw-r--r--tests/cancel4.c4
-rw-r--r--tests/condvar2.c2
-rw-r--r--tests/semaphore1.c4
-rw-r--r--tests/stress1.c271
-rw-r--r--tests/test.h18
-rw-r--r--tests/tsd1.c38
9 files changed, 398 insertions, 62 deletions
diff --git a/tests/Bmakefile b/tests/Bmakefile
index 285239a..60b0a75 100644
--- a/tests/Bmakefile
+++ b/tests/Bmakefile
@@ -91,11 +91,12 @@ PASSES= loadfree.pass \
mutex6s.pass mutex6es.pass mutex6rs.pass \
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \
mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \
- count1.pass once1.pass once2.pass once3.pass once4.pass tsd1.pass \
+ count1.pass once1.pass once2.pass once3.pass once4.pass \
self2.pass \
cancel1.pass cancel2.pass \
semaphore4.pass semaphore4t.pass \
- delay1.pass delay2.pass eyal1.pass \
+ barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \
+ tsd1.pass delay1.pass delay2.pass eyal1.pass \
condvar3.pass condvar3_1.pass condvar3_2.pass condvar3_3.pass \
condvar4.pass condvar5.pass condvar6.pass \
condvar7.pass condvar8.pass condvar9.pass \
@@ -108,9 +109,8 @@ PASSES= loadfree.pass \
cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \
priority1.pass priority2.pass inherit1.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
- barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \
exception1.pass exception2.pass exception3.pass \
- cancel9.pass create3.pass
+ cancel9.pass create3.pass stress1.pass
BENCHRESULTS = \
benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
@@ -220,7 +220,7 @@ benchtest2.bench:
benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
-barrier1.pass:
+barrier1.pass: semaphore4.pass
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
barrier4.pass: barrier3.pass
@@ -234,6 +234,7 @@ cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
cancel7.pass: kill1.pass
cancel8.pass: cancel7.pass
+cancel9.pass: cancel8.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -339,7 +340,7 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
-tsd1.pass: join1.pass
+stress1.pass: barrier5.pass
+tsd1.pass: barrier5.pass join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
-cancel9.pass: cancel8.pass
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index a789e19..641164d 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -86,10 +86,11 @@ TESTS = sizes loadfree \
mutex4 mutex6 mutex6n mutex6e mutex6r \
mutex6s mutex6es mutex6rs \
mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \
- count1 once1 once2 once3 once4 tsd1 self2 \
+ count1 once1 once2 once3 once4 self2 \
cancel1 cancel2 \
semaphore4 semaphore4t \
- delay1 delay2 eyal1 \
+ barrier1 barrier2 barrier3 barrier4 barrier5 \
+ tsd1 delay1 delay2 eyal1 \
condvar3 condvar3_1 condvar3_2 condvar3_3 \
condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \
errno1 \
@@ -100,10 +101,12 @@ TESTS = sizes loadfree \
cleanup0 cleanup1 cleanup2 cleanup3 \
priority1 priority2 inherit1 \
spin1 spin2 spin3 spin4 \
- barrier1 barrier2 barrier3 barrier4 barrier5 \
exception1 exception2 exception3 \
cancel9 create3
+STRESSTESTS = \
+ stress1
+
BENCHTESTS = \
benchtest1 benchtest2 benchtest3 benchtest4 benchtest5
@@ -112,6 +115,7 @@ STATICTESTS = \
PASSES = $(TESTS:%=%.pass)
BENCHRESULTS = $(BENCHTESTS:%=%.bench)
+STRESSRESULTS = $(STRESSTESTS:%=%.pass)
STATICRESULTS = $(STATICTESTS:%=%.pass)
help:
@@ -121,6 +125,8 @@ help:
@ $(ECHO) "make clean GCE (to test using GCE dll with C++ (EH) applications)"
@ $(ECHO) "make clean GC-bench (to benchtest using GNU C dll with C cleanup code)"
@ $(ECHO) "make clean GCE-bench (to benchtest using GNU C dll with C++ exception handling)"
+ @ $(ECHO) "make clean GC-stress (to stresstest using GNU C dll with C cleanup code)"
+ @ $(ECHO) "make clean GCE-stress (to stresstest using GNU C dll with C++ exception handling)"
@ $(ECHO) "make clean GC-static (to test using GC static lib with C (no EH) applications)"
all:
@@ -146,12 +152,24 @@ GCE-bench:
GC-static:
$(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C -DPTW32_STATIC_LIB" DLL="" all-static
+GC-stress:
+ $(ECHO) Stress tests can take a long time since they are trying to
+ $(ECHO) expose weaknesses that may be intermittant or statistically rare.
+ $(ECHO) A pass does not prove correctness, but may give greater confidence.
+ $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" all-stress
+
+GCE-stress:
+ $(MAKE) TEST=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" all-stress
+
all-pass: $(PASSES)
@ $(ECHO) ALL TESTS PASSED! Congratulations!
all-bench: $(BENCHRESULTS)
@ $(ECHO) BENCH TESTS COMPLETED.
+all-stress: $(STRESSRESULTS)
+ @ $(ECHO) STRESS TESTS COMPLETED.
+
all-static: $(STATICRESULTS)
@ $(ECHO) ALL STATIC TESTS PASSED! Congratulations!
@ $(ECHO) Build and test the DLL to run all tests.
@@ -163,7 +181,9 @@ benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
-barrier1.pass:
+stress1.pass:
+
+barrier1.pass: semaphore4.pass
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
barrier4.pass: barrier3.pass
@@ -178,6 +198,7 @@ cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
cancel7.pass: kill1.pass
cancel8.pass: cancel7.pass
+cancel9.pass: cancel8.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -283,10 +304,9 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
-tsd1.pass: join1.pass
+tsd1.pass: barrier5.pass join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
-cancel9.pass: cancel8.pass
sizes.pass: sizes.exe
@ $(ECHO) Running $*
diff --git a/tests/Makefile b/tests/Makefile
index 5c73009..8fa72b4 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -95,11 +95,12 @@ PASSES= sizes.pass loadfree.pass \
mutex6s.pass mutex6es.pass mutex6rs.pass \
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \
mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \
- count1.pass once1.pass once2.pass once3.pass once4.pass tsd1.pass \
+ count1.pass once1.pass once2.pass once3.pass once4.pass \
self2.pass \
cancel1.pass cancel2.pass \
semaphore4.pass semaphore4t.pass \
- delay1.pass delay2.pass eyal1.pass \
+ barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \
+ tsd1.pass delay1.pass delay2.pass eyal1.pass \
condvar3.pass condvar3_1.pass condvar3_2.pass condvar3_3.pass \
condvar4.pass condvar5.pass condvar6.pass \
condvar7.pass condvar8.pass condvar9.pass \
@@ -113,27 +114,33 @@ PASSES= sizes.pass loadfree.pass \
cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \
priority1.pass priority2.pass inherit1.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
- barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \
exception1.pass exception2.pass exception3.pass \
- cancel9.pass create3.pass
+ cancel9.pass create3.pass
BENCHRESULTS = \
benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
+STRESSRESULTS = \
+ stress1.pass
+
STATICRESULTS = \
self1.pass
help:
@ $(ECHO) Run one of the following command lines:
- @ $(ECHO) nmake clean VC (to test using VC dll with VC (no EH) applications)
- @ $(ECHO) nmake clean VCX (to test using VC dll with VC++ (EH) applications)
- @ $(ECHO) nmake clean VCE (to test using the VCE dll with VC++ EH applications)
- @ $(ECHO) nmake clean VSE (to test using VSE dll with VC (SEH) applications)
- @ $(ECHO) nmake clean VC-bench (to benchtest using VC dll with C bench app)
- @ $(ECHO) nmake clean VCX-bench (to benchtest using VC dll with C++ bench app)
- @ $(ECHO) nmake clean VCE-bench (to benchtest using VCE dll with C++ bench app)
- @ $(ECHO) nmake clean VSE-bench (to benchtest using VSE dll with SEH bench app)
- @ $(ECHO) nmake clean VC-static (to test using VC static lib with VC (no EH) applications)
+ @ $(ECHO) nmake clean VC (to test using VC dll with VC (no EH) apps)
+ @ $(ECHO) nmake clean VC-bench (to benchtest using VC dll with C bench apps)
+ @ $(ECHO) nmake clean VC-stress (to stresstest using VC dll with C stress apps)
+ @ $(ECHO) nmake clean VC-static (to test using VC static lib with VC (no EH) apps)
+ @ $(ECHO) nmake clean VCX (to test using VC dll with VC++ (EH) applications)
+ @ $(ECHO) nmake clean VCX-bench (to benchtest using VC dll with C++ bench apps)
+ @ $(ECHO) nmake clean VCX-stress (to stresstest using VC dll with C++ stress apps)
+ @ $(ECHO) nmake clean VCE (to test using the VCE dll with VC++ EH applications)
+ @ $(ECHO) nmake clean VCE-bench (to benchtest using VCE dll with C++ bench apps)
+ @ $(ECHO) nmake clean VCE-stress (to stresstest using VCE dll with C++ stress apps)
+ @ $(ECHO) nmake clean VSE (to test using VSE dll with VC (SEH) apps)
+ @ $(ECHO) nmake clean VSE-bench (to benchtest using VSE dll with SEH bench apps)
+ @ $(ECHO) nmake clean VSE-stress (to stresstest using VSE dll with SEH stress apps)
all:
@ nmake clean VC
@@ -141,6 +148,7 @@ all:
@ nmake clean VCE
@ nmake clean VSE
@ nmake clean VC-bench
+ @ nmake clean VC-stress
# This allows an individual test application to be made using the default lib.
# e.g. nmake clean test cancel3.exe
@@ -152,6 +160,9 @@ tests: $(CPLIB) $(CPDLL) $(CPHDR) $(QAPC) $(PASSES)
benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(XXLIBS) $(BENCHRESULTS)
@ $(ECHO) ALL BENCH TESTS DONE.
+stresstests: $(CPLIB) $(CPDLL) $(CPHDR) $(STRESSRESULTS)
+ @ $(ECHO) ALL STRESS TESTS DONE.
+
statictests: $(CPLIB) $(CPDLL) $(CPHDR) $(STATICRESULTS)
@ $(ECHO) ALL STATIC TESTS DONE.
@ $(ECHO) Build and test the DLL to run all tests.
@@ -176,30 +187,48 @@ $(BENCHRESULTS): $*.exe
@ $(ECHO) ...... Done
@ $(TOUCH) $*.bench
+$(STRESSRESULTS): $*.exe
+ @ $(ECHO) ... Running $(TEST) stresstest: $*.exe
+ @ .\$*.exe
+ @ $(ECHO) ...... Done
+ @ $(TOUCH) $*.pass
+
+VC:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" tests
+
VCE:
@ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" tests
VSE:
@ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" tests
-VC:
- @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" tests
-
VCX:
@ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" tests
+VC-bench:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" XXLIBS="benchlib.o" benchtests
+
VCE-bench:
@ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" XXLIBS="benchlib.o" benchtests
VSE-bench:
@ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" XXLIBS="benchlib.o" benchtests
-VC-bench:
- @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" XXLIBS="benchlib.o" benchtests
-
VCX-bench:
@ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" XXLIBS="benchlib.o" benchtests
+VC-stress:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" stresstests
+
+VCE-stress:
+ @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" stresstests
+
+VSE-stress:
+ @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" stresstests
+
+VCX-stress:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" stresstests
+
VC-static:
@ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="" EHFLAGS="$(VCFLAGS) /DPTW32_STATIC_LIB" statictests
@@ -244,7 +273,10 @@ benchtest2.bench:
benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
-barrier1.pass:
+
+stress1.pass:
+
+barrier1.pass: semaphore4.pass
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
barrier4.pass: barrier3.pass
@@ -258,6 +290,7 @@ cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
cancel7.pass: kill1.pass
cancel8.pass: cancel7.pass
+cancel9.pass: cancel8.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -363,7 +396,6 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
-tsd1.pass: join1.pass
+tsd1.pass: barrier5.pass join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
-cancel9.pass: cancel8.pass
diff --git a/tests/cancel4.c b/tests/cancel4.c
index 1561ea6..6d6d3dc 100644
--- a/tests/cancel4.c
+++ b/tests/cancel4.c
@@ -112,10 +112,10 @@ mythread(void * arg)
assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0);
/*
- * We wait up to 10 seconds, waking every 0.1 seconds,
+ * We wait up to 2 seconds, waking every 0.1 seconds,
* for a cancelation to be applied to us.
*/
- for (bag->count = 0; bag->count < 100; bag->count++)
+ for (bag->count = 0; bag->count < 20; bag->count++)
Sleep(100);
return (void *) result;
diff --git a/tests/condvar2.c b/tests/condvar2.c
index cfc68af..33f1d3f 100644
--- a/tests/condvar2.c
+++ b/tests/condvar2.c
@@ -102,7 +102,7 @@ main()
abstime.tv_sec = currSysTime.time;
abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
- abstime.tv_sec += 5;
+ abstime.tv_sec += 1;
assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT);
diff --git a/tests/semaphore1.c b/tests/semaphore1.c
index b5b2050..4327e73 100644
--- a/tests/semaphore1.c
+++ b/tests/semaphore1.c
@@ -86,7 +86,7 @@ thr(void * arg)
if ( result == -1 )
{
int err = errno;
- perror("thread: sem_trywait 1: expected error"); // No error
+ perror("thread: sem_trywait 1: expect an EAGAIN error"); // No error
assert(err == EAGAIN);
}
else
@@ -131,7 +131,7 @@ main()
if ( result == -1 )
{
int err = errno;
- perror("main: sem_trywait 1: expected error"); // No error
+ perror("main: sem_trywait 1: expect an EAGAIN error"); // No error
assert(err == EAGAIN);
}
else
diff --git a/tests/stress1.c b/tests/stress1.c
new file mode 100644
index 0000000..b8d1c77
--- /dev/null
+++ b/tests/stress1.c
@@ -0,0 +1,271 @@
+/*
+ * stress1.c
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Test Synopsis:
+ * - Stress test condition variables, mutexes, semaphores.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - Correct accounting of semaphore and condition variable waiters.
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * Attempting to expose race conditions in cond vars, semaphores etc.
+ * - Master attempts to signal slave close to when timeout is due.
+ * - Master and slave do battle continuously until main tells them to stop.
+ * - Afterwards, the CV must be successfully destroyed (will return an
+ * error if there are waiters (including any internal semaphore waiters,
+ * which, if there are, cannot not be real waiters).
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - CV is successfully destroyed.
+ *
+ * Fail Criteria:
+ * - CV destroy fails.
+ */
+
+#include "test.h"
+#include <string.h>
+#include <sys/timeb.h>
+
+
+const unsigned int ITERATIONS = 1000;
+
+static pthread_t master, slave;
+typedef struct {
+ int value;
+ pthread_cond_t cv;
+ pthread_mutex_t mx;
+} mysig_t;
+
+static int allExit;
+static mysig_t control = {0, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};
+static pthread_barrier_t startBarrier, readyBarrier, holdBarrier;
+static int timeoutCount = 0;
+static int signalsTakenCount = 0;
+static int signalsSent = 0;
+static int bias = 0;
+static int timeout = 10; // Must be > 0
+
+enum {
+ CTL_STOP = -1
+};
+
+/*
+ * Returns abstime 'milliseconds' from 'now'.
+ */
+struct timespec *
+millisecondsFromNow (struct timespec * time, int millisecs)
+{
+ struct _timeb currSysTime;
+ int64_t nanosecs, secs;
+ const int64_t NANOSEC_PER_MILLISEC = 1000000;
+ const int64_t NANOSEC_PER_SEC = 1000000000;
+
+ /* get current system time and add millisecs */
+ _ftime(&currSysTime);
+
+ nanosecs = ((int64_t) (millisecs + currSysTime.millitm)) * NANOSEC_PER_MILLISEC;
+ if (nanosecs >= NANOSEC_PER_SEC)
+ {
+ secs = currSysTime.time + 1;
+ nanosecs %= NANOSEC_PER_SEC;
+ }
+ else
+ {
+ secs = currSysTime.time;
+ }
+
+ time->tv_nsec = (long)nanosecs;
+ time->tv_sec = (long)secs;
+
+ return time;
+}
+
+void *
+masterThread (void * arg)
+{
+ int dither = (int) arg;
+
+ timeout = (int) arg;
+
+ pthread_barrier_wait(&startBarrier);
+
+ do
+ {
+ int sleepTime;
+
+ assert(pthread_mutex_lock(&control.mx) == 0);
+ control.value = timeout;
+ assert(pthread_mutex_unlock(&control.mx) == 0);
+
+ /*
+ * We are attempting to send the signal close to when the slave
+ * is due to timeout. We feel around by adding some [non-random] dither.
+ *
+ * with dither added, sleep time range is 2*timeout peak-to-peak centred on timeout,
+ * e.g.
+ * if timeout = 10 then dither = 20 and
+ * sleep millisecs is: 5 <= ms <= 15
+ *
+ * The bias value attempts to apply some negative feedback to keep
+ * the ratio of timeouts to signals taken close to 1:1.
+ * bias changes more slowly than dither so as to average more.
+ */
+ if (signalsSent % timeout == 0)
+ {
+ if (timeoutCount > signalsTakenCount)
+ {
+ bias++;
+ }
+ else if (timeoutCount < signalsTakenCount)
+ {
+ bias--;
+ }
+ if (bias < -timeout || bias > timeout)
+ {
+ timeout++;
+ }
+ }
+ dither = (dither + 1 ) % (timeout * 2);
+ sleepTime = (timeout - bias + dither) / 2;
+ Sleep(sleepTime);
+ assert(pthread_cond_signal(&control.cv) == 0);
+ signalsSent++;
+
+ pthread_barrier_wait(&holdBarrier);
+ pthread_barrier_wait(&readyBarrier);
+ }
+ while (!allExit);
+
+ return NULL;
+}
+
+void *
+slaveThread (void * arg)
+{
+ struct timespec time;
+
+ pthread_barrier_wait(&startBarrier);
+
+ do
+ {
+ assert(pthread_mutex_lock(&control.mx) == 0);
+ if (pthread_cond_timedwait(&control.cv,
+ &control.mx,
+ millisecondsFromNow(&time, control.value)) == ETIMEDOUT)
+ {
+ timeoutCount++;
+ }
+ else
+ {
+ signalsTakenCount++;
+ }
+ assert(pthread_mutex_unlock(&control.mx) == 0);
+
+ pthread_barrier_wait(&holdBarrier);
+ pthread_barrier_wait(&readyBarrier);
+ }
+ while (!allExit);
+
+ return NULL;
+}
+
+int
+main ()
+{
+ unsigned int i;
+
+ assert(pthread_barrier_init(&startBarrier, NULL, 3) == 0);
+ assert(pthread_barrier_init(&readyBarrier, NULL, 3) == 0);
+ assert(pthread_barrier_init(&holdBarrier, NULL, 3) == 0);
+
+ assert(pthread_create(&master, NULL, masterThread, (void *) timeout) == 0);
+ assert(pthread_create(&slave, NULL, slaveThread, NULL) == 0);
+
+ allExit = FALSE;
+
+ pthread_barrier_wait(&startBarrier);
+
+ for (i = 1; !allExit; i++)
+ {
+ pthread_barrier_wait(&holdBarrier);
+ if (i >= ITERATIONS)
+ {
+ allExit = TRUE;
+ }
+ pthread_barrier_wait(&readyBarrier);
+ }
+
+ assert(pthread_join(slave, NULL) == 0);
+ assert(pthread_join(master, NULL) == 0);
+
+ printf("Signals sent = %d\nWait timeouts = %d\nSignals taken = %d\nBias = %d\nTimeout = %d\n",
+ signalsSent,
+ timeoutCount,
+ signalsTakenCount,
+ (int) bias,
+ timeout);
+
+ /* Cleanup */
+ assert(pthread_barrier_destroy(&holdBarrier) == 0);
+ assert(pthread_barrier_destroy(&readyBarrier) == 0);
+ assert(pthread_barrier_destroy(&startBarrier) == 0);
+ assert(pthread_cond_destroy(&control.cv) == 0);
+ assert(pthread_mutex_destroy(&control.mx) == 0);
+
+ /* Success. */
+ return 0;
+}
diff --git a/tests/test.h b/tests/test.h
index 11498cd..3132c69 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -47,6 +47,15 @@
#define PTW32_THREAD_NULL_ID {NULL,0}
+#if defined(__MINGW32__)
+#include <stdint.h>
+#elif defined(__BORLANDC__)
+#define int64_t ULONGLONG
+#else
+#define int64_t _int64
+#endif
+
+
char * error_string[] = {
"ZERO_or_EOK",
"EPERM",
@@ -109,13 +118,8 @@ char * error_string[] = {
# define ASSERT_TRACE 1
#endif
-/*
- * Trick to force the compiler to not optimise out dead or obvious expressions.
- */
-int ptw32_assert_force = 1;
-
# define assert(e) \
- (ptw32_assert_force && (e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
+ ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
"Assertion succeeded: (%s), file %s, line %d\n", \
#e, __FILE__, (int) __LINE__), \
fflush(stderr) : \
@@ -125,7 +129,7 @@ int ptw32_assert_force = 1;
int assertE;
# define assert_e(e, o, r) \
- (ptw32_assert_force && ((assertE = e) o (r)) ? ((ASSERT_TRACE) ? fprintf(stderr, \
+ (((assertE = e) o (r)) ? ((ASSERT_TRACE) ? fprintf(stderr, \
"Assertion succeeded: (%s), file %s, line %d\n", \
#e, __FILE__, (int) __LINE__), \
fflush(stderr) : \
diff --git a/tests/tsd1.c b/tests/tsd1.c
index 6e21d2a..4d89165 100644
--- a/tests/tsd1.c
+++ b/tests/tsd1.c
@@ -34,6 +34,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
*
+ * --------------------------------------------------------------------------
+ *
* Description:
* -
*
@@ -77,10 +79,15 @@
#include <sched.h>
#include "test.h"
+enum {
+ NUM_THREADS = 100
+};
+
static pthread_key_t key = NULL;
-static int accesscount[10];
-static int thread_set[10];
-static int thread_destroyed[10];
+static int accesscount[NUM_THREADS];
+static int thread_set[NUM_THREADS];
+static int thread_destroyed[NUM_THREADS];
+static pthread_barrier_t startBarrier;
static void
destroy_key(void * arg)
@@ -117,10 +124,7 @@ setkey(void * arg)
static void *
mythread(void * arg)
{
- while (key == NULL)
- {
- sched_yield();
- }
+ (void) pthread_barrier_wait(&startBarrier);
setkey(arg);
@@ -134,22 +138,24 @@ main()
{
int i;
int fail = 0;
- pthread_t thread[10];
+ pthread_t thread[NUM_THREADS];
- for (i = 1; i < 5; i++)
+ assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0);
+
+ for (i = 1; i < NUM_THREADS/2; i++)
{
accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
}
- Sleep(2000);
-
/*
* Here we test that existing threads will get a key created
* for them.
*/
assert(pthread_key_create(&key, destroy_key) == 0);
+ (void) pthread_barrier_wait(&startBarrier);
+
/*
* Test main thread key.
*/
@@ -160,16 +166,16 @@ main()
* Here we test that new threads will get a key created
* for them.
*/
- for (i = 5; i < 10; i++)
+ for (i = NUM_THREADS/2; i < NUM_THREADS; i++)
{
- accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
+ accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
}
/*
* Wait for all threads to complete.
*/
- for (i = 1; i < 10; i++)
+ for (i = 1; i < NUM_THREADS; i++)
{
int result = 0;
@@ -178,7 +184,9 @@ main()
assert(pthread_key_delete(key) == 0);
- for (i = 1; i < 10; i++)
+ assert(pthread_barrier_destroy(&startBarrier) == 0);
+
+ for (i = 1; i < NUM_THREADS; i++)
{
/*
* The counter is incremented once when the key is set to