diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/Bmakefile | 15 | ||||
| -rw-r--r-- | tests/GNUmakefile | 32 | ||||
| -rw-r--r-- | tests/Makefile | 76 | ||||
| -rw-r--r-- | tests/cancel4.c | 4 | ||||
| -rw-r--r-- | tests/condvar2.c | 2 | ||||
| -rw-r--r-- | tests/semaphore1.c | 4 | ||||
| -rw-r--r-- | tests/stress1.c | 271 | ||||
| -rw-r--r-- | tests/test.h | 18 | ||||
| -rw-r--r-- | tests/tsd1.c | 38 | 
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 | 
