From 19299847fdd32094b28377db1aea61b0f605dc8b Mon Sep 17 00:00:00 2001 From: rpj Date: Sun, 1 Jul 2001 13:49:38 +0000 Subject: 2001-07-01 Ross Johnson Contributed by - Alexander Terekhov. * condvar.c: Fixed lost signal bug reported by Timur Aydin (taydin@snet.net). [RPJ (me) didn't translate the original algorithm correctly.] * semaphore.c: Added sem_post_multiple; this is a useful routine, but it doesn't appear to be standard. For now it's not an exported function. tests/ChangeLog: 2001-07-01 Ross Johnson * benchtest3.c: New; timing mutexes. * benchtest4.c: New; time mutexes. * condvar3_1.c: Fixed bug - Alexander Terekhov * condvar3_3.c: New test. 2001-06-25 Ross Johnson * priority1.c: New test. * priority2.c: New test. * inherit1.c: New test. * benchtest1.c: New; timing mutexes. * benchtest2.c: New; timing mutexes. * mutex4.c: Modified to test all mutex types. --- tests/ChangeLog | 19 +++- tests/GNUmakefile | 45 ++++++-- tests/Makefile | 39 +++++-- tests/benchtest.h | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/benchtest1.c | 116 +++++++++++++++----- tests/benchtest2.c | 198 ++++++++++++++++++++++++--------- tests/benchtest3.c | 169 ++++++++++++++++++++++++++++ tests/benchtest4.c | 150 +++++++++++++++++++++++++ tests/condvar3.c | 8 +- tests/condvar3_1.c | 26 ++++- tests/condvar3_3.c | 100 +++++++++++++++++ 11 files changed, 1072 insertions(+), 112 deletions(-) create mode 100644 tests/benchtest.h create mode 100644 tests/benchtest3.c create mode 100644 tests/benchtest4.c create mode 100644 tests/condvar3_3.c diff --git a/tests/ChangeLog b/tests/ChangeLog index 231d9fe..f99d1be 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,11 +1,18 @@ +2001-07-01 Ross Johnson + + * benchtest3.c: New; timing mutexes. + * benchtest4.c: New; time mutexes. + * condvar3_1.c: Fixed bug - Alexander Terekhov + * condvar3_3.c: New test. + 2001-06-25 Ross Johnson - priority1.c: New test. - priority2.c: New test. - inherit1.c: New test. - benchtest1.c: New; timing mutexes. - benchtest2.c: New; timing mutexes. - mutex4.c: Modified to test all mutex types. + * priority1.c: New test. + * priority2.c: New test. + * inherit1.c: New test. + * benchtest1.c: New; timing mutexes. + * benchtest2.c: New; timing mutexes. + * mutex4.c: Modified to test all mutex types. 2001-06-8 Ross Johnson diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 2eabdae..b952eed 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -41,41 +41,54 @@ TESTS = loadfree \ exit2 exit3 \ join0 join1 join2 mutex2 mutex3 mutex4 mutex6 mutex6n mutex6e mutex6r \ count1 once1 tsd1 self2 cancel1 cancel2 eyal1 \ - condvar3 condvar3_1 condvar3_2 condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ + condvar3 condvar3_1 condvar3_2 condvar3_3 \ + condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 \ context1 cancel3 cancel4 cancel5 \ cleanup0 cleanup1 cleanup2 cleanup3 \ priority1 priority2 inherit1 \ - exception1 exception2 \ - benchtest1 benchtest2 \ - exception3 + exception1 exception2 exception3 -PASSES = $(TESTS:%=%.pass) +BENCHTESTS = \ + benchtest1 benchtest2 benchtest3 benchtest4 + +PASSES = $(TESTS:%=%.pass) +BENCHRESULTS = $(BENCHTESTS:%=%.bench) default: @ $(ECHO) Run one of the following command lines: @ $(ECHO) nmake clean GCE (to test using GNU C dll with C++ exception handling) @ $(ECHO) nmake clean GC (to test using GNU C dll with C cleanup code) + @ $(ECHO) nmake clean GCE-bench (to benchtest using GNU C dll with C++ exception handling) + @ $(ECHO) nmake clean GC-bench (to benchtest using GNU C dll with C cleanup code) auto: @ $(MAKE) clean GCE @ $(MAKE) clean GC GC: - $(MAKE) GCX=GC XXCFLAGS="-x c" all-GC + $(MAKE) GCX=GC XXCFLAGS="-x c" all-pass GCE: - $(MAKE) GCX=GCE XXCFLAGS="-mthreads -x c++" all-GCE + $(MAKE) GCX=GCE XXCFLAGS="-mthreads -x c++" all-pass -all-GC: $(PASSES) - @ $(ECHO) ALL TESTS PASSED! Congratulations! +GC-bench: + $(MAKE) GCX=GC XXCFLAGS="-x c" all-bench -all-GCE: $(PASSES) +GCE-bench: + $(MAKE) GCX=GCE XXCFLAGS="-mthreads -x c++" all-bench + +all-pass: $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! -benchtest1.pass: mutex3.pass -benchtest2.pass: benchtest1.pass +all-bench: $(BENCHRESULTS) + @ $(ECHO) BENCH TESTS COMPLETED. + +benchtest1.bench: +benchtest2.bench: +benchtest3.bench: +benchtest4.bench: cancel1.pass: create1.pass cancel2.pass: cancel1.pass cancel2_1.pass: cancel2.pass @@ -92,6 +105,7 @@ condvar2_1.pass: condvar2.pass join2.pass condvar3.pass: create1.pass condvar2.pass condvar3_1.pass: condvar3.pass join2.pass condvar3_2.pass: condvar3_1.pass +condvar3_3.pass: condvar3_2.pass condvar4.pass: create1.pass condvar5.pass: condvar4.pass condvar6.pass: condvar5.pass @@ -144,6 +158,12 @@ tsd1.pass: join1.pass @ $(ECHO) Passed @ $(TOUCH) $@ +%.bench: %.exe $(LIB) $(DLL) $(HDR) + @ $(ECHO) Running $* + $* + @ $(ECHO) Done + @ $(TOUCH) $@ + %.exe: %.c @ $(ECHO) Compiling $@ @ $(ECHO) $(CC) $(CFLAGS) -o $@ $^ $(INCLUDES) -L. -lpthread$(GCX) @@ -174,3 +194,4 @@ clean: - $(RM) *.pdb - $(RM) *.exe - $(RM) *.pass + - $(RM) *.bench diff --git a/tests/Makefile b/tests/Makefile index d7b36b0..7fd32af 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -48,7 +48,8 @@ PASSES= loadfree.pass \ self2.pass \ cancel1.pass cancel2.pass \ eyal1.pass \ - condvar3.pass condvar3_1.pass condvar3_2.pass condvar4.pass condvar5.pass condvar6.pass \ + condvar3.pass condvar3_1.pass condvar3_2.pass condvar3_3.pass \ + condvar4.pass condvar5.pass condvar6.pass \ condvar7.pass condvar8.pass condvar9.pass \ errno1.pass \ rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass rwlock5.pass rwlock6.pass rwlock7.pass \ @@ -56,14 +57,19 @@ PASSES= loadfree.pass \ cancel3.pass cancel4.pass cancel5.pass \ cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \ priority1.pass priority2.pass inherit1.pass \ - exception1.pass exception2.pass \ - benchtest1.pass benchtest2.pass exception3.pass \ + exception1.pass exception2.pass exception3.pass + +BENCHRESULTS = \ + benchtest1.pass benchtest2.pass all: @ $(ECHO) Run one of the following command lines: @ $(ECHO) nmake clean VCE (to test using MSVC dll with C++ exception handling) @ $(ECHO) nmake clean VSE (to test using MSVC dll with structured exception handling) @ $(ECHO) nmake clean VC (to test using MSVC dll with C cleanup code) + @ $(ECHO) nmake clean VCE-bench (to benchtest using MSVC dll with C++ exception handling) + @ $(ECHO) nmake clean VSE-bench (to benchtest using MSVC dll with structured exception handling) + @ $(ECHO) nmake clean VC-bench (to benchtest using MSVC dll with C cleanup code) auto: @ nmake clean VCE @@ -73,12 +79,21 @@ auto: tests: $(CPLIB) $(CPDLL) $(CPHDR) $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! +benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(BENCHRESULTS) + @ $(ECHO) ALL BENCH TESTS DONE. + $(PASSES): $*.exe @ $(ECHO) ... Running $(TEST) test: $*.exe @ .\$*.exe @ $(ECHO) ...... Passed @ $(TOUCH) $*.pass +$(BENCHRESULTS): $*.exe + @ $(ECHO) ... Running $(TEST) benchtest: $*.exe + @ .\$*.exe + @ $(ECHO) ...... Done + @ $(TOUCH) $*.bench + VCE: @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" tests @@ -88,6 +103,15 @@ VSE: VC: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" tests +VCE-bench: + @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" benchtests + +VSE-bench: + @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" benchtests + +VC-bench: + @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" benchtests + .c.exe: @ $(ECHO) Compiling $@ @ $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) @@ -115,9 +139,11 @@ clean: - $(RM) *.o - $(RM) *.exe - $(RM) *.pass + - $(RM) *.bench -benchtest1.pass: mutex3.pass -benchtest2.pass: benchtest1.pass +benchtest1.bench: +benchtest2.bench: +benchtest3.bench: cancel1.pass: create1.pass cancel2.pass: cancel1.pass cancel3.pass: context1.pass @@ -133,6 +159,7 @@ condvar2_1.pass: condvar2.pass join2.pass condvar3.pass: create1.pass condvar2.pass condvar3_1.pass: condvar3.pass join2.pass condvar3_2.pass: condvar3_1.pass +condvar3_3.pass: condvar3_2.pass condvar4.pass: create1.pass condvar5.pass: condvar4.pass condvar6.pass: condvar5.pass @@ -177,5 +204,3 @@ rwlock7.pass: rwlock6.pass self1.pass: self2.pass: create1.pass tsd1.pass: join1.pass - - diff --git a/tests/benchtest.h b/tests/benchtest.h new file mode 100644 index 0000000..98d2bbe --- /dev/null +++ b/tests/benchtest.h @@ -0,0 +1,314 @@ +/****************************************************************************************/ + +#include "../config.h" + +enum { + OLD_WIN32CS, + OLD_WIN32MUTEX +}; + +static int old_mutex_use = OLD_WIN32CS; + +struct old_mutex_t_ { + HANDLE mutex; + CRITICAL_SECTION cs; +}; + +typedef struct old_mutex_t_ * old_mutex_t; + +struct old_mutexattr_t_ { + int pshared; +}; + +typedef struct old_mutexattr_t_ * old_mutexattr_t; + +static BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; +static HINSTANCE ptw32_h_kernel32; + +#define PTW32_OBJECT_AUTO_INIT ((void *) -1) + +static int +old_mutex_init(old_mutex_t *mutex, const old_mutexattr_t *attr) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL) + { + return EINVAL; + } + + mx = (old_mutex_t) calloc(1, sizeof(*mx)); + + if (mx == NULL) + { + result = ENOMEM; + goto FAIL0; + } + + mx->mutex = 0; + + if (attr != NULL + && *attr != NULL + && (*attr)->pshared == PTHREAD_PROCESS_SHARED + ) + { + result = ENOSYS; + } + else + { + CRITICAL_SECTION cs; + + /* + * Load KERNEL32 and try to get address of TryEnterCriticalSection + */ + ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); + ptw32_try_enter_critical_section = (BOOL (WINAPI *)(LPCRITICAL_SECTION)) + +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress(ptw32_h_kernel32, + (const TCHAR *)TEXT("TryEnterCriticalSection")); +#else + GetProcAddress(ptw32_h_kernel32, + (LPCSTR) "TryEnterCriticalSection"); +#endif + + if (ptw32_try_enter_critical_section != NULL) + { + InitializeCriticalSection(&cs); + if ((*ptw32_try_enter_critical_section)(&cs)) + { + LeaveCriticalSection(&cs); + } + else + { + /* + * Not really supported (Win98?). + */ + ptw32_try_enter_critical_section = NULL; + } + DeleteCriticalSection(&cs); + } + + if (ptw32_try_enter_critical_section == NULL) + { + (void) FreeLibrary(ptw32_h_kernel32); + ptw32_h_kernel32 = 0; + } + + if (old_mutex_use == OLD_WIN32CS) + { + InitializeCriticalSection(&mx->cs); + } + else if (old_mutex_use == OLD_WIN32MUTEX) + { + mx->mutex = CreateMutex (NULL, + FALSE, + NULL); + + if (mx->mutex == 0) + { + result = EAGAIN; + } + } + else + { + result = EINVAL; + } + } + + if (result != 0 && mx != NULL) + { + free(mx); + mx = NULL; + } + +FAIL0: + *mutex = mx; + + return(result); +} + + +static int +old_mutex_lock(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + /* + * Don't use initialisers when benchtesting. + */ + result = EINVAL; + } + + mx = *mutex; + + if (result == 0) + { + if (mx->mutex == 0) + { + EnterCriticalSection(&mx->cs); + } + else + { + result = (WaitForSingleObject(mx->mutex, INFINITE) + == WAIT_OBJECT_0) + ? 0 + : EINVAL; + } + } + + return(result); +} + +static int +old_mutex_unlock(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + mx = *mutex; + + if (mx != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + if (mx->mutex == 0) + { + LeaveCriticalSection(&mx->cs); + } + else + { + result = (ReleaseMutex (mx->mutex) ? 0 : EINVAL); + } + } + else + { + result = EINVAL; + } + + return(result); +} + + +static int +old_mutex_trylock(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + /* + * Don't use initialisers when benchtesting. + */ + result = EINVAL; + } + + mx = *mutex; + + if (result == 0) + { + if (mx->mutex == 0) + { + if (ptw32_try_enter_critical_section == NULL) + { + result = 0; + } + else if ((*ptw32_try_enter_critical_section)(&mx->cs) != TRUE) + { + result = EBUSY; + } + } + else + { + DWORD status; + + status = WaitForSingleObject (mx->mutex, 0); + + if (status != WAIT_OBJECT_0) + { + result = ((status == WAIT_TIMEOUT) + ? EBUSY + : EINVAL); + } + } + } + + return(result); +} + + +static int +old_mutex_destroy(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL + || *mutex == NULL) + { + return EINVAL; + } + + if (*mutex != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + mx = *mutex; + + if ((result = old_mutex_trylock(&mx)) == 0) + { + *mutex = NULL; + + (void) old_mutex_unlock(&mx); + + if (mx->mutex == 0) + { + DeleteCriticalSection(&mx->cs); + } + else + { + result = (CloseHandle (mx->mutex) ? 0 : EINVAL); + } + + if (result == 0) + { + mx->mutex = 0; + free(mx); + } + else + { + *mutex = mx; + } + } + } + else + { + result = EINVAL; + } + + if (ptw32_try_enter_critical_section != NULL) + { + (void) FreeLibrary(ptw32_h_kernel32); + ptw32_h_kernel32 = 0; + } + + return(result); +} + +/****************************************************************************************/ diff --git a/tests/benchtest1.c b/tests/benchtest1.c index 883c24f..8514fa4 100644 --- a/tests/benchtest1.c +++ b/tests/benchtest1.c @@ -14,6 +14,9 @@ #include #endif +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES #define ITERATIONS 10000000L pthread_mutex_t mx; @@ -40,24 +43,22 @@ long overHeadMilliSecs = 0; void runTest (char * testNameString, int mType) { -#ifdef PTHREAD_MUTEX_DEFAULT - pthread_mutexattr_settype(&ma, mType); +#ifdef PTW32_MUTEX_TYPES + assert(pthread_mutexattr_settype(&ma, mType) == 0); #endif - pthread_mutex_init(&mx, &ma); + assert(pthread_mutex_init(&mx, &ma) == 0); TESTSTART - (void) pthread_mutex_lock(&mx); - (void) pthread_mutex_unlock(&mx); + assert(pthread_mutex_lock(&mx) == 0); + assert(pthread_mutex_unlock(&mx) == 0); TESTSTOP - pthread_mutex_destroy(&mx); + assert(pthread_mutex_destroy(&mx) == 0); - durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - - overHeadMilliSecs; + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; - printf( "%-25s %15ld %15ld %15.3f\n", - testNameString, - ITERATIONS, + printf( "%-40s %15ld %15.3f\n", + testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); } @@ -66,47 +67,104 @@ runTest (char * testNameString, int mType) int main (int argc, char *argv[]) { + CRITICAL_SECTION cs; + old_mutex_t ox; + pthread_mutexattr_init(&ma); - printf( "Single thread, non-blocking mutex locks/unlocks.\n\n"); - printf( "%-25s %15s %15s %15s\n", - "Test", - "Iterations", - "Total(msec)", - "lock/unlock(usec)"); + printf( "========================================================================\n"); + printf( "\nNon-blocking mutex lock plus unlock.\n%ld iterations\n\n", + ITERATIONS); + printf( "%-40s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + printf( "------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ TESTSTART + assert(1 == 1); + assert(1 == 1); TESTSTOP - durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - - overHeadMilliSecs; + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; - printf( "%-25s %15ld %15ld\n", - "Overhead", - ITERATIONS, - durationMilliSecs); - overHeadMilliSecs = durationMilliSecs; + InitializeCriticalSection(&cs); + + TESTSTART + assert((EnterCriticalSection(&cs), 1) == 1); + assert((LeaveCriticalSection(&cs), 1) == 1); + TESTSTOP + + DeleteCriticalSection(&cs); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-40s %15ld %15.3f\n", + "Simple Critical Section", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + + old_mutex_use = OLD_WIN32CS; + assert(old_mutex_init(&ox, NULL) == 0); + + TESTSTART + assert(old_mutex_lock(&ox) == 0); + assert(old_mutex_unlock(&ox) == 0); + TESTSTOP + + assert(old_mutex_destroy(&ox) == 0); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Critical Section (WNT)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + + old_mutex_use = OLD_WIN32MUTEX; + assert(old_mutex_init(&ox, NULL) == 0); + + TESTSTART + assert(old_mutex_lock(&ox) == 0); + assert(old_mutex_unlock(&ox) == 0); + TESTSTOP + + assert(old_mutex_destroy(&ox) == 0); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Win32 Mutex (W9x)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + printf( "........................................................................\n"); /* * Now we can start the actual tests */ -#ifdef PTHREAD_MUTEX_DEFAULT - runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); - runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); + runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); - runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); + runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); - runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); + runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif + printf( "========================================================================\n"); + /* * End of tests. */ diff --git a/tests/benchtest2.c b/tests/benchtest2.c index f2932b9..a049961 100644 --- a/tests/benchtest2.c +++ b/tests/benchtest2.c @@ -17,9 +17,14 @@ #include #endif +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES #define ITERATIONS 100000L pthread_mutex_t gate1, gate2; +old_mutex_t ox1, ox2; +CRITICAL_SECTION cs1, cs2; pthread_mutexattr_t ma; long durationMilliSecs; long overHeadMilliSecs = 0; @@ -55,6 +60,22 @@ overheadThread(void * arg) } +void * +oldThread(void * arg) +{ + do + { + (void) old_mutex_lock(&ox1); + (void) old_mutex_lock(&ox2); + (void) old_mutex_unlock(&ox1); + sched_yield(); + (void) old_mutex_unlock(&ox2); + } + while (running); + + return NULL; +} + void * workerThread(void * arg) { @@ -71,22 +92,34 @@ workerThread(void * arg) return NULL; } +void * +CSThread(void * arg) +{ + do + { + EnterCriticalSection(&cs1); + EnterCriticalSection(&cs2); + LeaveCriticalSection(&cs1); + sched_yield(); + LeaveCriticalSection(&cs2); + } + while (running); + + return NULL; +} + void runTest (char * testNameString, int mType) { -#ifdef PTHREAD_MUTEX_DEFAULT - pthread_mutexattr_settype(&ma, mType); +#ifdef PTW32_MUTEX_TYPES + assert(pthread_mutexattr_settype(&ma, mType) == 0); #endif - pthread_mutex_init(&gate1, &ma); - pthread_mutex_init(&gate2, &ma); - - (void) pthread_mutex_lock(&gate1); - (void) pthread_mutex_lock(&gate2); - + assert(pthread_mutex_init(&gate1, &ma) == 0); + assert(pthread_mutex_init(&gate2, &ma) == 0); + assert(pthread_mutex_lock(&gate1) == 0); + assert(pthread_mutex_lock(&gate2) == 0); running = 1; - - (void) pthread_create(&worker, NULL, workerThread, NULL); - + assert(pthread_create(&worker, NULL, workerThread, NULL) == 0); TESTSTART (void) pthread_mutex_unlock(&gate1); sched_yield(); @@ -94,23 +127,15 @@ runTest (char * testNameString, int mType) (void) pthread_mutex_lock(&gate1); (void) pthread_mutex_lock(&gate2); TESTSTOP - running = 0; - - (void) pthread_mutex_unlock(&gate2); - (void) pthread_mutex_unlock(&gate1); - - (void) pthread_join(worker, NULL); - - pthread_mutex_destroy(&gate2); - pthread_mutex_destroy(&gate1); - - durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - - overHeadMilliSecs; - - printf( "%-25s %15ld %15ld %15.3f\n", - testNameString, - ITERATIONS, + assert(pthread_mutex_unlock(&gate2) == 0); + assert(pthread_mutex_unlock(&gate1) == 0); + assert(pthread_join(worker, NULL) == 0); + assert(pthread_mutex_destroy(&gate2) == 0); + assert(pthread_mutex_destroy(&gate1) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS / 4 /* Four locks/unlocks per iteration */); } @@ -119,60 +144,131 @@ runTest (char * testNameString, int mType) int main (int argc, char *argv[]) { - pthread_mutexattr_init(&ma); + assert(pthread_mutexattr_init(&ma) == 0); - printf( "Two threads, blocking mutex locks/unlocks.\n\n"); + printf( "========================================================================\n"); + printf( "\nBlocking mutex lock plus unlock.\n"); + printf("%ld iterations, four locks/unlocks per iteration.\n\n", ITERATIONS); - printf( "%-25s %15s %15s %15s\n", - "Test", - "Iterations", - "Total(msec)", - "lock/unlock(usec)"); + printf( "%-40s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + printf( "------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ running = 1; + assert(pthread_create(&worker, NULL, overheadThread, NULL) == 0); + TESTSTART + sched_yield(); + sched_yield(); + TESTSTOP + running = 0; + assert(pthread_join(worker, NULL) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; - (void) pthread_create(&worker, NULL, overheadThread, NULL); + InitializeCriticalSection(&cs1); + InitializeCriticalSection(&cs2); + EnterCriticalSection(&cs1); + EnterCriticalSection(&cs2); + running = 1; + assert(pthread_create(&worker, NULL, CSThread, NULL) == 0); TESTSTART + LeaveCriticalSection(&cs1); sched_yield(); + LeaveCriticalSection(&cs2); + EnterCriticalSection(&cs1); + EnterCriticalSection(&cs2); TESTSTOP - running = 0; + LeaveCriticalSection(&cs2); + LeaveCriticalSection(&cs1); + assert(pthread_join(worker, NULL) == 0); + DeleteCriticalSection(&cs2); + DeleteCriticalSection(&cs1); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "Simple Critical Section", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS / 4 ); - (void) pthread_join(worker, NULL); - pthread_mutex_destroy(&gate2); - pthread_mutex_destroy(&gate1); + old_mutex_use = OLD_WIN32CS; + assert(old_mutex_init(&ox1, NULL) == 0); + assert(old_mutex_init(&ox2, NULL) == 0); + assert(old_mutex_lock(&ox1) == 0); + assert(old_mutex_lock(&ox2) == 0); + running = 1; + assert(pthread_create(&worker, NULL, oldThread, NULL) == 0); + TESTSTART + (void) old_mutex_unlock(&ox1); + sched_yield(); + (void) old_mutex_unlock(&ox2); + (void) old_mutex_lock(&ox1); + (void) old_mutex_lock(&ox2); + TESTSTOP + running = 0; + assert(old_mutex_unlock(&ox1) == 0); + assert(old_mutex_unlock(&ox2) == 0); + assert(pthread_join(worker, NULL) == 0); + assert(old_mutex_destroy(&ox2) == 0); + assert(old_mutex_destroy(&ox1) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Critical Section (WNT)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS / 4); - durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - - overHeadMilliSecs; - printf( "%-25s %15ld %15ld\n", - "Overhead", - ITERATIONS, - durationMilliSecs); + old_mutex_use = OLD_WIN32MUTEX; + assert(old_mutex_init(&ox1, NULL) == 0); + assert(old_mutex_init(&ox2, NULL) == 0); + assert(old_mutex_lock(&ox1) == 0); + assert(old_mutex_lock(&ox2) == 0); + running = 1; + assert(pthread_create(&worker, NULL, oldThread, NULL) == 0); + TESTSTART + (void) old_mutex_unlock(&ox1); + sched_yield(); + (void) old_mutex_unlock(&ox2); + (void) old_mutex_lock(&ox1); + (void) old_mutex_lock(&ox2); + TESTSTOP + running = 0; + assert(old_mutex_unlock(&ox1) == 0); + assert(old_mutex_unlock(&ox2) == 0); + assert(pthread_join(worker, NULL) == 0); + assert(old_mutex_destroy(&ox2) == 0); + assert(old_mutex_destroy(&ox1) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Win32 Mutex (W9x)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS / 4); - overHeadMilliSecs = durationMilliSecs; + printf( "........................................................................\n"); /* * Now we can start the actual tests */ -#ifdef PTHREAD_MUTEX_DEFAULT - runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); - runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); + runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); - runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); + runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); - runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); + runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Blocking locks", 0); #endif + printf( "========================================================================\n"); /* * End of tests. */ diff --git a/tests/benchtest3.c b/tests/benchtest3.c new file mode 100644 index 0000000..c789fab --- /dev/null +++ b/tests/benchtest3.c @@ -0,0 +1,169 @@ +/* + * benchtest3.c + * + * Measure time taken to complete an elementary operation. + * + * - Mutex + * Single thread iteration over a trylock on a locked mutex for each mutex type. + */ + +#include "test.h" +#include + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES +#define ITERATIONS 10000000L + +pthread_mutex_t mx; +old_mutex_t ox; +pthread_mutexattr_t ma; +struct _timeb currSysTimeStart; +struct _timeb currSysTimeStop; +long durationMilliSecs; +long overHeadMilliSecs = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ + - (_TStart.time*1000+_TStart.millitm)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; + +#define TESTSTOP \ + }; _ftime(&currSysTimeStop); if (j + k == i) j++; } + + +void * +trylockThread (void * arg) +{ + TESTSTART + (void) pthread_mutex_trylock(&mx); + TESTSTOP + + return NULL; +} + + +void * +oldTrylockThread (void * arg) +{ + TESTSTART + (void) old_mutex_trylock(&ox); + TESTSTOP + + return NULL; +} + + +void +runTest (char * testNameString, int mType) +{ + pthread_t t; + +#ifdef PTW32_MUTEX_TYPES + (void) pthread_mutexattr_settype(&ma, mType); +#endif + assert(pthread_mutex_init(&mx, &ma) == 0); + assert(pthread_mutex_lock(&mx) == 0); + assert(pthread_create(&t, NULL, trylockThread, 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_mutex_unlock(&mx) == 0); + assert(pthread_mutex_destroy(&mx) == 0); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-40s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); +} + + +int +main (int argc, char *argv[]) +{ + pthread_t t; + + assert(pthread_mutexattr_init(&ma) == 0); + + printf( "========================================================================\n"); + printf( "\nTrylock on a locked mutex.\n"); + printf( "%ld iterations.\n\n", ITERATIONS); + printf( "%-40s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + printf( "------------------------------------------------------------------------\n"); + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + TESTSTART + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + + old_mutex_use = OLD_WIN32CS; + assert(old_mutex_init(&ox, NULL) == 0); + assert(old_mutex_lock(&ox) == 0); + assert(pthread_create(&t, NULL, oldTrylockThread, 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(old_mutex_unlock(&ox) == 0); + assert(old_mutex_destroy(&ox) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Critical Section (WNT)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + old_mutex_use = OLD_WIN32MUTEX; + assert(old_mutex_init(&ox, NULL) == 0); + assert(old_mutex_lock(&ox) == 0); + assert(pthread_create(&t, NULL, oldTrylockThread, 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(old_mutex_unlock(&ox) == 0); + assert(old_mutex_destroy(&ox) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Win32 Mutex (W9x)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + printf( "........................................................................\n"); + + /* + * Now we can start the actual tests + */ +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( "========================================================================\n"); + + /* + * End of tests. + */ + + pthread_mutexattr_destroy(&ma); + + return 0; +} diff --git a/tests/benchtest4.c b/tests/benchtest4.c new file mode 100644 index 0000000..c343db7 --- /dev/null +++ b/tests/benchtest4.c @@ -0,0 +1,150 @@ +/* + * benchtest4.c + * + * Measure time taken to complete an elementary operation. + * + * - Mutex + * Single thread iteration over trylock/unlock for each mutex type. + */ + +#include "test.h" +#include + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES +#define ITERATIONS 10000000L + +pthread_mutex_t mx; +old_mutex_t ox; +pthread_mutexattr_t ma; +struct _timeb currSysTimeStart; +struct _timeb currSysTimeStop; +long durationMilliSecs; +long overHeadMilliSecs = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ + - (_TStart.time*1000+_TStart.millitm)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; + +#define TESTSTOP \ + }; _ftime(&currSysTimeStop); if (j + k == i) j++; } + + +void +oldRunTest (char * testNameString, int mType) +{ +} + + +void +runTest (char * testNameString, int mType) +{ +#ifdef PTW32_MUTEX_TYPES + pthread_mutexattr_settype(&ma, mType); +#endif + pthread_mutex_init(&mx, &ma); + + TESTSTART + (void) pthread_mutex_trylock(&mx); + (void) pthread_mutex_unlock(&mx); + TESTSTOP + + pthread_mutex_destroy(&mx); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-40s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); +} + + +int +main (int argc, char *argv[]) +{ + pthread_mutexattr_init(&ma); + + printf( "========================================================================\n"); + printf( "Non-blocking mutex trylock plus unlock.\n"); + printf( "%ld iterations.\n\n", ITERATIONS); + printf( "%-40s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + printf( "------------------------------------------------------------------------\n"); + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + TESTSTART + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + old_mutex_use = OLD_WIN32CS; + assert(old_mutex_init(&ox, NULL) == 0); + TESTSTART + (void) old_mutex_trylock(&ox); + (void) old_mutex_unlock(&ox); + TESTSTOP + assert(old_mutex_destroy(&ox) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Critical Section (WNT)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + old_mutex_use = OLD_WIN32MUTEX; + assert(old_mutex_init(&ox, NULL) == 0); + TESTSTART + (void) old_mutex_trylock(&ox); + (void) old_mutex_unlock(&ox); + TESTSTOP + assert(old_mutex_destroy(&ox) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-40s %15ld %15.3f\n", + "PT Mutex using a Win32 Mutex (W9x)", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + printf( "........................................................................\n"); + + /* + * Now we can start the actual tests + */ +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( "========================================================================\n"); + + /* + * End of tests. + */ + + pthread_mutexattr_destroy(&ma); + + return 0; +} diff --git a/tests/condvar3.c b/tests/condvar3.c index 673feb5..ef71946 100644 --- a/tests/condvar3.c +++ b/tests/condvar3.c @@ -59,13 +59,19 @@ enum { void * mythread(void * arg) { + int result = 0; + assert(pthread_mutex_lock(&mutex) == 0); shared++; assert(pthread_mutex_unlock(&mutex) == 0); - assert(pthread_cond_signal(&cv) == 0); + if ((result = pthread_cond_signal(&cv)) != 0) + { + printf("Error = %s\n", error_string[result]); + } + assert(result == 0); return (void *) 0; } diff --git a/tests/condvar3_1.c b/tests/condvar3_1.c index f9bb0c6..ea5f33f 100644 --- a/tests/condvar3_1.c +++ b/tests/condvar3_1.c @@ -47,11 +47,13 @@ #include static pthread_cond_t cv; +static pthread_cond_t cv1; static pthread_mutex_t mutex; static struct timespec abstime = { 0, 0 }; static int timedout = 0; static int signaled = 0; static int awoken = 0; +static int waiting = 0; enum { NUMTHREADS = 60 @@ -64,6 +66,9 @@ mythread(void * arg) assert(pthread_mutex_lock(&mutex) == 0); + if ( ++waiting == NUMTHREADS) + assert(pthread_cond_signal(&cv1) == 0); + result = pthread_cond_timedwait(&cv, &mutex, &abstime); if (result == ETIMEDOUT) { @@ -91,6 +96,7 @@ main() const DWORD NANOSEC_PER_MILLISEC = 1000000; assert(pthread_cond_init(&cv, NULL) == 0); + assert(pthread_cond_init(&cv1, NULL) == 0); assert(pthread_mutex_init(&mutex, NULL) == 0); @@ -109,6 +115,10 @@ main() assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); } + do { + assert(pthread_cond_wait(&cv1,&mutex) == 0); + } while ( NUMTHREADS != waiting ); + assert(pthread_mutex_unlock(&mutex) == 0); for (i = NUMTHREADS/3; i <= 2*NUMTHREADS/3; i++) @@ -120,9 +130,13 @@ main() for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_join(t[i], (void **) &result) == 0); - assert(result == i); + assert(result == i); } + fprintf(stderr, "awk = %d\n", awoken); + fprintf(stderr, "sig = %d\n", signaled); + fprintf(stderr, "tot = %d\n", timedout); + assert(signaled == awoken); assert(timedout == NUMTHREADS - signaled); @@ -131,11 +145,11 @@ main() if (result != 0) { fprintf(stderr, "Result = %s\n", error_string[result]); - fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); - fprintf(stderr, "\tWaitersUnblocked = %ld\n", cv->nWaitersUnblocked); - fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); - fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); - fflush(stderr); + fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); + fprintf(stderr, "\tWaitersUnblocked = %ld\n", cv->nWaitersUnblocked); + fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); + fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); + fflush(stderr); } assert(result == 0); } diff --git a/tests/condvar3_3.c b/tests/condvar3_3.c new file mode 100644 index 0000000..43e6f3a --- /dev/null +++ b/tests/condvar3_3.c @@ -0,0 +1,100 @@ +/* + * File: condvar3_3.c + * + * Test Synopsis: + * - Test timeouts and lost signals on a CV. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait does not return ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +/* Timur Aydin (taydin@snet.net) */ + +#include "test.h" + +#include + +pthread_cond_t cnd; +pthread_mutex_t mtx; + +int main() +{ + int rc; + + struct timespec abstime = { 0, 0 }; + struct _timeb currSysTime; + const DWORD NANOSEC_PER_MILLISEC = 1000000; + + assert(pthread_cond_init(&cnd, 0) == 0); + assert(pthread_mutex_init(&mtx, 0) == 0); + + /* get current system time */ + _ftime(&currSysTime); + + abstime.tv_sec = currSysTime.time; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; + abstime.tv_sec += 1; + + /* Here pthread_cond_timedwait should time out after one second. */ + + assert(pthread_mutex_lock(&mtx) == 0); + + assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT); + + assert(pthread_mutex_unlock(&mtx) == 0); + + /* Here, the condition variable is signaled, but there are no + threads waiting on it. The signal should be lost and + the next pthread_cond_timedwait should time out too. */ + + assert(pthread_mutex_lock(&mtx) == 0); + + assert((rc = pthread_cond_signal(&cnd)) == 0); + + assert(pthread_mutex_unlock(&mtx) == 0); + + assert(pthread_mutex_lock(&mtx) == 0); + + abstime.tv_sec = currSysTime.time; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; + abstime.tv_sec += 1; + + assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT); + + assert(pthread_mutex_unlock(&mtx) == 0); + + return 0; +} -- cgit v1.2.3