summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>1999-03-07 18:02:06 +0000
committerrpj <rpj>1999-03-07 18:02:06 +0000
commit1e9697f3e8f5da2f710a98d9ae8ce3105e61a4a6 (patch)
treec97ac587bcdd05ec65a184d188756489fb3f710d
parentb7a68044db80c822d86ef20dbdd179ed34291390 (diff)
Mon Mar 8 11:18:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
* misc.c (CancelableWait): Ensure cancelEvent handle is the lowest indexed element in the handles array. Enhance test for abandoned objects. * pthread.h (PTHREAD_MUTEX_INITIALIZER): Trailing elements not initialised are set to zero by the compiler. This avoids the problem of initialising the opaque critical section element in it. (PTHREAD_COND_INITIALIZER): Ditto. * semaphore.c (_pthread_sem_timedwait): Check sem == NULL earlier. Sun Mar 7 12:31:14 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * condvar.c (pthread_cond_init): set semaphore initial value to 0, not 1. cond_timedwait was returning signaled immediately. * misc.c (CancelableWait): Place the cancel event handle first in the handle table for WaitForMultipleObjects. This ensures that the cancel event is recognised and acted apon if both objects happen to be signaled together. * private.c (_pthread_cond_test_init_lock): Initialise and destroy. * implement.h (_pthread_cond_test_init_lock): Add extern. * global.c (_pthread_cond_test_init_lock): Add declaration. * condvar.c (pthread_cond_destroy): check for valid initialised CV; flag destroyed CVs as invalid. (pthread_cond_init): pthread_cond_t is no longer just a pointer. This is because PTHREAD_COND_INITIALIZER needs state info to reside in pthread_cond_t so that it can initialise on first use. Will work on making pthread_cond_t (and other objects like it) opaque again, if possible, later. (cond_timedwait): add check for statically initialisation of CV; initialise on first use. (pthread_cond_signal): check for valid CV. (pthread_cond_broadcast): check for valid CV. (_cond_check_need_init): Add. * pthread.h (PTHREAD_COND_INITIALIZER): Fix. (pthread_cond_t): no longer a pointer to pthread_cond_t_. (pthread_cond_t_): add 'staticinit' and 'valid' elements. tests/ChangeLog Sun Mar 7 10:41:52 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au> * Makefile (condvar3, condvar4): Add tests. * condvar4.c (General): Reduce to simple test case; prerequisite is condvar3.c; add description. * condvar3.c (General): Reduce to simple test case; prerequisite is condvar2.c; add description. * condvar2.c (General): Reduce to simple test case; prerequisite is condvar1.c; add description. * condvar1.c (General): Reduce to simple test case; add description. * Template.c (Comments): Add generic test detail.
-rw-r--r--ChangeLog46
-rw-r--r--condvar.c210
-rw-r--r--global.c6
-rw-r--r--implement.h1
-rw-r--r--misc.c52
-rw-r--r--mutex.c2
-rw-r--r--private.c6
-rw-r--r--pthread.h53
-rw-r--r--semaphore.c10
-rw-r--r--tests/Makefile139
-rw-r--r--tests/condvar2.c156
-rw-r--r--tests/condvar3.c212
-rw-r--r--tests/condvar4.c227
13 files changed, 658 insertions, 462 deletions
diff --git a/ChangeLog b/ChangeLog
index cdce59a..5f50d64 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,49 @@
+Mon Mar 8 11:18:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (CancelableWait): Ensure cancelEvent handle is the lowest
+ indexed element in the handles array. Enhance test for abandoned
+ objects.
+
+ * pthread.h (PTHREAD_MUTEX_INITIALIZER): Trailing elements not
+ initialised are set to zero by the compiler. This avoids the
+ problem of initialising the opaque critical section element in it.
+ (PTHREAD_COND_INITIALIZER): Ditto.
+
+ * semaphore.c (_pthread_sem_timedwait): Check sem == NULL earlier.
+
+Sun Mar 7 12:31:14 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (pthread_cond_init): set semaphore initial value
+ to 0, not 1. cond_timedwait was returning signaled immediately.
+
+ * misc.c (CancelableWait): Place the cancel event handle first
+ in the handle table for WaitForMultipleObjects. This ensures that
+ the cancel event is recognised and acted apon if both objects
+ happen to be signaled together.
+
+ * private.c (_pthread_cond_test_init_lock): Initialise and destroy.
+
+ * implement.h (_pthread_cond_test_init_lock): Add extern.
+
+ * global.c (_pthread_cond_test_init_lock): Add declaration.
+
+ * condvar.c (pthread_cond_destroy): check for valid initialised CV;
+ flag destroyed CVs as invalid.
+ (pthread_cond_init): pthread_cond_t is no longer just a pointer.
+ This is because PTHREAD_COND_INITIALIZER needs state info to reside
+ in pthread_cond_t so that it can initialise on first use. Will work on
+ making pthread_cond_t (and other objects like it) opaque again, if
+ possible, later.
+ (cond_timedwait): add check for statically initialisation of
+ CV; initialise on first use.
+ (pthread_cond_signal): check for valid CV.
+ (pthread_cond_broadcast): check for valid CV.
+ (_cond_check_need_init): Add.
+
+ * pthread.h (PTHREAD_COND_INITIALIZER): Fix.
+ (pthread_cond_t): no longer a pointer to pthread_cond_t_.
+ (pthread_cond_t_): add 'staticinit' and 'valid' elements.
+
Sun Feb 21 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
* pthread.h (PTHREAD_MUTEX_INITIALIZER): missing braces around
diff --git a/condvar.c b/condvar.c
index eb549b5..8fca94c 100644
--- a/condvar.c
+++ b/condvar.c
@@ -12,6 +12,67 @@
#include "pthread.h"
#include "implement.h"
+static int
+_cond_check_need_init(pthread_cond_t *cond)
+{
+ int result = 0;
+
+ /*
+ * The following guarded test is specifically for statically
+ * initialised condition variables (via PTHREAD_COND_INITIALIZER).
+ *
+ * Note that by not providing this synchronisation we risk
+ * introducing race conditions into applications which are
+ * correctly written.
+ *
+ * Approach
+ * --------
+ * We know that static condition variables will not be PROCESS_SHARED
+ * so we can serialise access to internal state using
+ * Win32 Critical Sections rather than Win32 Mutexes.
+ *
+ * We still have a problem in that we would like a per-mutex
+ * lock, but attempting to create one will again lead
+ * to a race condition. We are forced to use a global
+ * lock in this instance.
+ *
+ * If using a single global lock slows applications down too much,
+ * multiple global locks could be created and hashed on some random
+ * value associated with each mutex, the pointer perhaps. At a guess,
+ * a good value for the optimal number of global locks might be
+ * the number of processors + 1.
+ *
+ * We need to maintain the following per-cv state independently:
+ * - cv staticinit (true iff cv is static and still
+ * needs to be initialised)
+ * - cv valid (false iff cv has been destroyed)
+ *
+ * For example, in this implementation a cv initialised by
+ * PTHREAD_COND_INITIALIZER will be 'valid' but uninitialised until
+ * the thread attempts to use it. It can also be destroyed (made invalid)
+ * before ever being used.
+ */
+ EnterCriticalSection(&_pthread_cond_test_init_lock);
+
+ /*
+ * We got here because staticinit tested true, possibly under race
+ * conditions. Check staticinit again inside the critical section
+ * and only initialise if the cv is valid (not been destroyed).
+ * If a static cv has been destroyed, the application can
+ * re-initialise it only by calling pthread_cond_init()
+ * explicitly.
+ */
+ if (cond->staticinit && cond->valid)
+ {
+ result = pthread_cond_init(cond, NULL);
+ }
+
+ LeaveCriticalSection(&_pthread_cond_test_init_lock);
+
+ return(result);
+}
+
+
int
pthread_condattr_init (pthread_condattr_t * attr)
/*
@@ -281,7 +342,19 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
*/
{
int result = EAGAIN;
- pthread_cond_t cv = NULL;
+
+ if (cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Assuming any race condition here is harmless.
+ */
+ if (cond->valid && !cond->staticinit)
+ {
+ return EBUSY;
+ }
if ((attr != NULL && *attr != NULL) &&
((*attr)->pshared == PTHREAD_PROCESS_SHARED))
@@ -295,37 +368,34 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
goto FAIL0;
}
- cv = (pthread_cond_t) calloc (1, sizeof (*cv));
-
- if (cv == NULL)
- {
- result = ENOMEM;
- goto FAIL0;
- }
-
- cv->waiters = 0;
- cv->wasBroadcast = FALSE;
+ cond->waiters = 0;
+ cond->wasBroadcast = FALSE;
- if (_pthread_sem_init (&(cv->sema), 0, 1) != 0)
+ if (_pthread_sem_init (&(cond->sema), 0, 0) != 0)
{
goto FAIL0;
}
- if (pthread_mutex_init (&(cv->waitersLock), NULL) != 0)
+ if (pthread_mutex_init (&(cond->waitersLock), NULL) != 0)
{
goto FAIL1;
}
- cv->waitersDone = CreateEvent (
+ cond->waitersDone = CreateEvent (
0,
(int) FALSE, /* manualReset */
(int) FALSE, /* setSignaled */
NULL);
- if (cv->waitersDone == NULL)
+ if (cond->waitersDone == NULL)
{
goto FAIL2;
}
+ cond->staticinit = 0;
+
+ /* Mark as valid. */
+ cond->valid = 1;
+
result = 0;
goto DONE;
@@ -336,16 +406,13 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
* -------------
*/
FAIL2:
- (void) pthread_mutex_destroy (&(cv->waitersLock));
+ (void) pthread_mutex_destroy (&(cond->waitersLock));
FAIL1:
- (void) _pthread_sem_destroy (&(cv->sema));
- free (cv);
- cv = NULL;
+ (void) _pthread_sem_destroy (&(cond->sema));
FAIL0:
DONE:
- *cond = cv;
return (result);
} /* pthread_cond_init */
@@ -380,21 +447,26 @@ pthread_cond_destroy (pthread_cond_t * cond)
*/
{
int result = 0;
- pthread_cond_t cv;
- if (cond != NULL && *cond != NULL)
+ /*
+ * Assuming any race condition here is harmless.
+ */
+ if (cond == NULL || cond->valid == 0 || cond->staticinit == 1)
{
- cv = *cond;
-
- (void) _pthread_sem_destroy (&(cv->sema));
- (void) pthread_mutex_destroy (&(cv->waitersLock));
- (void) CloseHandle (cv->waitersDone);
-
- free (cv);
+ return EINVAL;
+ }
- *cond = NULL;
+ if (cond->waiters > 0)
+ {
+ return EBUSY;
}
+ (void) _pthread_sem_destroy (&(cond->sema));
+ (void) pthread_mutex_destroy (&(cond->waitersLock));
+ (void) CloseHandle (cond->waitersDone);
+
+ cond->valid = 0;
+
return (result);
}
@@ -404,15 +476,24 @@ cond_timedwait (pthread_cond_t * cond,
const struct timespec *abstime)
{
int result = 0;
- pthread_cond_t cv;
- int lastWaiter;
+ int internal_result = 0;
+ int lastWaiter = FALSE;
- cv = *cond;
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static condition variable. We check 'staticinit'
+ * again inside the guarded section of _cond_check_need_init()
+ * to avoid race conditions.
+ */
+ if (cond->staticinit == 1)
+ {
+ result = _cond_check_need_init(cond);
+ }
/*
- * OK to increment cv->waiters because the caller locked 'mutex'
+ * OK to increment cond->waiters because the caller locked 'mutex'
*/
- cv->waiters++;
+ cond->waiters++;
/*
* We keep the lock held just long enough to increment the count of
@@ -433,30 +514,30 @@ cond_timedwait (pthread_cond_t * cond,
* hence providing the
* mechanism for making pthread_cond_wait a cancellation
* point. We use the cleanup mechanism to ensure we
- * re-lock the mutex if we are cancelled.
+ * re-lock the mutex if we are cancelled.
*/
pthread_cleanup_push (pthread_mutex_lock, mutex);
- result = _pthread_sem_timedwait (&(cv->sema), abstime);
+ result = _pthread_sem_timedwait (&(cond->sema), abstime);
pthread_cleanup_pop (0);
}
- if ((result = pthread_mutex_lock (&(cv->waitersLock))) == 0)
+ if ((internal_result = pthread_mutex_lock (&(cond->waitersLock))) == 0)
{
/*
* By making the waiter responsible for decrementing
* its count we don't have to worry about having an internal
* mutex.
*/
- cv->waiters--;
+ cond->waiters--;
- lastWaiter = cv->wasBroadcast && (cv->waiters == 0);
+ lastWaiter = cond->wasBroadcast && (cond->waiters == 0);
- result = pthread_mutex_unlock (&(cv->waitersLock));
+ internal_result = pthread_mutex_unlock (&(cond->waitersLock));
}
- if (result == 0)
+ if (result == 0 && internal_result == 0)
{
if (lastWaiter)
{
@@ -464,7 +545,7 @@ cond_timedwait (pthread_cond_t * cond,
* If we are the last waiter on this broadcast
* let the thread doing the broadcast proceed
*/
- if (!SetEvent (cv->waitersDone))
+ if (!SetEvent (cond->waitersDone))
{
result = EINVAL;
}
@@ -646,15 +727,26 @@ pthread_cond_signal (pthread_cond_t * cond)
*/
{
int result = 0;
- pthread_cond_t cv = *cond;
+
+ if (cond == NULL || cond->valid == 0)
+ {
+ return EINVAL;
+ }
/*
- * If there aren't any waiters, then this is a no-op.
+ * No-op if the CV is static and hasn't been initialised yet.
*/
- if (cv->waiters > 0)
+ if (cond->staticinit == 1)
{
+ return 0;
+ }
- result = _pthread_sem_post (&(cv->sema));
+ /*
+ * If there aren't any waiters, then this is a no-op.
+ */
+ if (cond->waiters > 0)
+ {
+ result = _pthread_sem_post (&(cond->sema));
}
return (result);
@@ -700,27 +792,39 @@ pthread_cond_broadcast (pthread_cond_t * cond)
*/
{
int result = 0;
- pthread_cond_t cv = *cond;
int i;
- cv->wasBroadcast = TRUE;
+ if (cond == NULL || cond->valid == 0)
+ {
+ return EINVAL;
+ }
+
+ cond->wasBroadcast = TRUE;
+
+ /*
+ * No-op if the CV is static and hasn't been initialised yet.
+ */
+ if (cond->staticinit == 1)
+ {
+ return 0;
+ }
/*
* Wake up all waiters
*/
- for (i = cv->waiters; i > 0 && result == 0; i--)
+ for (i = cond->waiters; i > 0 && result == 0; i--)
{
- result = _pthread_sem_post (&(cv->sema));
+ result = _pthread_sem_post (&(cond->sema));
}
- if (cv->waiters > 0 && result == 0)
+ if (cond->waiters > 0 && result == 0)
{
/*
* Wait for all the awakened threads to acquire their part of
* the counting semaphore
*/
- if (WaitForSingleObject (cv->waitersDone, INFINITE) !=
+ if (WaitForSingleObject (cond->waitersDone, INFINITE) !=
WAIT_OBJECT_0)
{
diff --git a/global.c b/global.c
index a8bd69a..ecc3d27 100644
--- a/global.c
+++ b/global.c
@@ -20,5 +20,11 @@ pthread_key_t _pthread_cleanupKey = NULL;
*/
CRITICAL_SECTION _pthread_mutex_test_init_lock;
+/*
+ * Global lock for testing internal state of PTHREAD_COND_INITIALIZER
+ * created condition variables.
+ */
+CRITICAL_SECTION _pthread_cond_test_init_lock;
+
diff --git a/implement.h b/implement.h
index 2103027..4ee33a6 100644
--- a/implement.h
+++ b/implement.h
@@ -150,6 +150,7 @@ extern int _pthread_processInitialized;
extern pthread_key_t _pthread_selfThreadKey;
extern pthread_key_t _pthread_cleanupKey;
extern CRITICAL_SECTION _pthread_mutex_test_init_lock;
+extern CRITICAL_SECTION _pthread_cond_test_init_lock;
#include <pthread.h>
diff --git a/misc.c b/misc.c
index 025653c..df7af10 100644
--- a/misc.c
+++ b/misc.c
@@ -213,8 +213,12 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)
DWORD nHandles = 1;
DWORD status;
- handles[0] = waitHandle;
-
+ /*
+ * If both objects are signaled, then (status - WAIT_OBJECT_0)
+ * will be the lowest index value of all the signaled objects.
+ * We must ensure that a cancelation is recognised if this occurs by
+ * placing the cancelEvent handle first in the handle table.
+ */
if ((self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey))
!= NULL)
{
@@ -224,16 +228,14 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)
if (self->cancelState == PTHREAD_CANCEL_ENABLE)
{
- if ((handles[1] = self->cancelEvent) != NULL)
+ if ((handles[0] = self->cancelEvent) != NULL)
{
nHandles++;
}
}
}
- else
- {
- handles[1] = NULL;
- }
+
+ handles[nHandles - 1] = waitHandle;
status = WaitForMultipleObjects (
nHandles,
@@ -241,41 +243,36 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)
FALSE,
timeout);
-
if (status == WAIT_FAILED)
{
result = EINVAL;
-
}
else if (status == WAIT_TIMEOUT)
{
result = ETIMEDOUT;
}
- else if (status == WAIT_ABANDONED_0)
+ else if (status >= WAIT_ABANDONED_0 && status <= WAIT_ABANDONED_0 + nHandles - 1)
{
+ /*
+ * The waitHandle was a mutex object that was abandoned.
+ */
result = EINVAL;
}
else
{
/*
- * Either got the mutex or the cancel event
- * was signaled
+ * Either got the object or the cancel event
+ * was signaled, or both in which case the cancel
+ * event will be acted on.
*/
- switch (status - WAIT_OBJECT_0)
+ switch (status - WAIT_OBJECT_0 + 2 - nHandles)
{
case 0:
/*
- * Got the mutex
- */
- result = 0;
- break;
-
- case 1:
- /*
- * Got cancel request
+ * Got cancel request.
*/
- ResetEvent (handles[1]);
+ ResetEvent (handles[0]);
if (self != NULL && !self->implicit)
{
@@ -307,8 +304,15 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)
#endif /* _MSC_VER */
}
- /* Should never get to here. */
- result = EINVAL;
+ /* Should never get to here. */
+ result = EINVAL;
+ break;
+
+ case 1:
+ /*
+ * Got the object.
+ */
+ result = 0;
break;
default:
diff --git a/mutex.c b/mutex.c
index 578617d..b88eac4 100644
--- a/mutex.c
+++ b/mutex.c
@@ -451,7 +451,7 @@ pthread_mutex_lock(pthread_mutex_t *mutex)
* again inside the guarded section of _mutex_check_need_init()
* to avoid race conditions.
*/
- if (mutex->staticinit)
+ if (mutex->staticinit == 1)
{
result = _mutex_check_need_init(mutex);
}
diff --git a/private.c b/private.c
index 88a71ee..56062a1 100644
--- a/private.c
+++ b/private.c
@@ -56,9 +56,10 @@ _pthread_processInitialize (void)
}
/*
- * Set up the global mutex test and init check lock.
+ * Set up the global test and init check locks.
*/
InitializeCriticalSection(&_pthread_mutex_test_init_lock);
+ InitializeCriticalSection(&_pthread_cond_test_init_lock);
return (_pthread_processInitialized);
@@ -111,9 +112,10 @@ _pthread_processTerminate (void)
}
/*
- * Destroy up the global mutex test and init check lock.
+ * Destroy the global test and init check locks.
*/
DeleteCriticalSection(&_pthread_mutex_test_init_lock);
+ DeleteCriticalSection(&_pthread_cond_test_init_lock);
_pthread_processInitialized = FALSE;
}
diff --git a/pthread.h b/pthread.h
index e17a2c6..da40f48 100644
--- a/pthread.h
+++ b/pthread.h
@@ -421,7 +421,7 @@ extern "C"
typedef struct pthread_key_t_ *pthread_key_t;
typedef struct pthread_mutex_t_ pthread_mutex_t;
typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t;
- typedef struct pthread_cond_t_ *pthread_cond_t;
+ typedef struct pthread_cond_t_ pthread_cond_t;
typedef struct pthread_condattr_t_ *pthread_condattr_t;
@@ -458,20 +458,6 @@ extern "C"
#define PTHREAD_CANCEL_DEFERRED 1
/*
- * ====================
- * ====================
- * Mutex
- * ====================
- * ====================
- */
-
-/*
- *
- */
-#define PTHREAD_MUTEX_INITIALIZER { 1, 1, 0, {NULL} }
-
-
-/*
* pthread_mutexattr_{get,set}pshared
* pthread_condattr_{get,set}pshared
*/
@@ -500,20 +486,11 @@ struct pthread_once_t_
/* to zero executes the user function */
};
-/*
- * ====================
- * ====================
- * Condition Variable
- * ====================
- * ====================
- */
-#define PTHREAD_COND_INITIALIZER { {0, 0}, 0, PTHREAD_MUTEX_INITIALIZER }
-
/*
* ====================
* ====================
- * Opaque Structure Definitions
+ * Structure Definitions
* ====================
* ====================
*/
@@ -587,9 +564,19 @@ struct pthread_attr_t_ {
};
+/*
+ * ====================
+ * ====================
+ * Mutex
+ * ====================
+ * ====================
+ */
+
+#define PTHREAD_MUTEX_INITIALIZER { 1, 1 /* Remaining are all 0 */ }
+
struct pthread_mutex_t_ {
- int staticinit;
- int valid;
+ int staticinit; /* Needs implicit init if 1. */
+ int valid; /* Not destroyed if 1. */
HANDLE mutex;
CRITICAL_SECTION cs;
};
@@ -609,9 +596,21 @@ struct pthread_key_t_ {
};
+/*
+ * ====================
+ * ====================
+ * Condition Variable
+ * ====================
+ * ====================
+ */
+
+#define PTHREAD_COND_INITIALIZER { 1, 1 /* Remaining are all 0 */ }
+
typedef HANDLE _pthread_sem_t;
struct pthread_cond_t_ {
+ int staticinit; /* Needs implicit init if 1. */
+ int valid; /* Not destroyed if 1. */
long waiters; /* # waiting threads */
pthread_mutex_t waitersLock; /* Mutex that guards access to
waiter count */
diff --git a/semaphore.c b/semaphore.c
index f3bd5c9..5f7d083 100644
--- a/semaphore.c
+++ b/semaphore.c
@@ -267,6 +267,11 @@ _pthread_sem_timedwait (_pthread_sem_t * sem, const struct timespec * abstime)
const DWORD MILLISEC_PER_SEC = 1000;
DWORD milliseconds;
+ if (sem == NULL)
+ {
+ return EINVAL;
+ }
+
if (abstime == NULL)
{
milliseconds = INFINITE;
@@ -286,10 +291,7 @@ _pthread_sem_timedwait (_pthread_sem_t * sem, const struct timespec * abstime)
currSysTime.millitm;
}
- return ((sem == NULL)
- ? EINVAL
- : pthreadCancelableTimedWait (*sem, milliseconds)
- );
+ return (pthreadCancelableTimedWait (*sem, milliseconds));
} /* _pthread_sem_timedwait */
diff --git a/tests/Makefile b/tests/Makefile
index 14228b7..dcbb7e0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,69 +1,70 @@
-# Makefile for the pthreads test suite.
-# If all of the .pass files can be created, the test suite has passed.
-
-
-CP = copy
-RM = erase
-MKDIR = mkdir
-TOUCH = echo Passed >
-ECHO = @echo
-
-#
-# Mingw32
-#
-CC = gcc
-CFLAGS = -g -O2 -UNDEBUG -Wall -o $@ $^
-BUILD_DIR = ..
-INCLUDES = -I./include
-LIBS = ./lib/libpthread32.a
-
-##
-## MSVC
-##
-#CC = cl
-#CFLAGS = /W3 /MT /nologo /Yd /Zi /Fe$@ $^
-#BUILD_DIR = ..
-#INCLUDES = -I.\include
-#LIBS = .\lib\pthread.lib
-
-HDR = .\include\pthread.h
-LIB = .\lib\libpthread32.a
-DLL = pthread.dll
-
-# If a test case returns a non-zero exit code to the shell, make will
-# stop.
-
-TESTS = count1 create1 equal1 exit1 exit2 exit3 \
- join1 eyal1 mutex1 mutex2 mutex3 \
- once1 self1 self2 condvar1 condvar2 condvar3 condvar4 tsd1
-
-PASSES = $(TESTS:%=%.pass)
-
-all: $(PASSES)
- @ $(ECHO) ALL TESTS PASSED! Congratulations!
-
-%.pass: %.exe $(LIB) $(DLL) $(HDR)
- $*
- @$(ECHO) Passed
- @ $(TOUCH) $@
-
-%.exe: %.c
- @ $(CC) $(CFLAGS) $(INCLUDES) $(LIBS)
-
-$(LIB):
- @- $(MKDIR) .\lib
- @ $(CP) $(BUILD_DIR)\$@ .\$@
-
-$(HDR):
- @- $(MKDIR) .\include
- @ $(CP) $(BUILD_DIR)\$@ .\$@
-
-$(DLL):
- @ $(CP) $(BUILD_DIR)\$@ .\$@
-
-clean:
- - $(RM) *.dll
- - $(RM) $(LIB)
- - $(RM) $(HDR)
- - $(RM) *.exe
- - $(RM) *.pass
+# Makefile for the pthreads test suite.
+# If all of the .pass files can be created, the test suite has passed.
+
+
+CP = copy
+RM = erase
+MKDIR = mkdir
+TOUCH = echo Passed >
+ECHO = @echo
+
+#
+# Mingw32
+#
+CC = gcc
+CFLAGS = -g -O2 -UNDEBUG -Wall -o $@ $^
+BUILD_DIR = ..
+INCLUDES = -I.
+LIBS = ./libpthread32.a
+
+##
+## MSVC
+##
+#CC = cl
+#CFLAGS = /W3 /MT /nologo /Yd /Zi /Fe$@ $^
+#BUILD_DIR = ..
+#INCLUDES = -I.
+#LIBS = pthread.lib
+
+HDR = pthread.h
+LIB = libpthread32.a
+DLL = pthread.dll
+
+# If a test case returns a non-zero exit code to the shell, make will
+# stop.
+
+TESTS = count1 create1 equal1 exit1 exit2 exit3 \
+ join1 mutex1 mutex2 mutex3 \
+ once1 self1 self2 condvar1 condvar2 condvar3 condvar4 tsd1
+
+PASSES = $(TESTS:%=%.pass)
+
+all: $(PASSES)
+ @ $(ECHO) ALL TESTS PASSED! Congratulations!
+
+%.pass: %.exe $(LIB) $(DLL) $(HDR)
+ $*
+ @$(ECHO) Passed
+ @ $(TOUCH) $@
+
+%.exe: %.c
+ @ $(CC) $(CFLAGS) $(INCLUDES) $(LIBS)
+
+$(LIB):
+ @ $(ECHO) Copying the library
+ @ $(CP) $(BUILD_DIR)\$@ .
+
+$(HDR):
+ @ $(ECHO) Copying the header file
+ @ $(CP) $(BUILD_DIR)\$@ .
+
+$(DLL):
+ @ $(ECHO) Copying the DLL
+ @ $(CP) $(BUILD_DIR)\$@ .
+
+clean:
+ - $(RM) *.dll
+ - $(RM) $(LIB)
+ - $(RM) $(HDR)
+ - $(RM) *.exe
+ - $(RM) *.pass
diff --git a/tests/condvar2.c b/tests/condvar2.c
index 107ed8f..66f3d7b 100644
--- a/tests/condvar2.c
+++ b/tests/condvar2.c
@@ -1,73 +1,83 @@
-/*
- * File: condvar1.c
- *
- * Test Synopsis:
- * - Test timed wait on a CV.
- *
- * Test Method (Validation or Falsification):
- * - Validation
- *
- * Requirements Tested:
- * -
- *
- * Features Tested:
- * -
- *
- * Cases Tested:
- * -
- *
- * Description:
- * - Because the CV is never signaled, we expect the wait to time out.
- *
- * 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.
- */
-
-#include "test.h"
-
-pthread_cond_t cv;
-pthread_mutex_t mutex;
-
-int
-main()
-{
- struct timespec abstime = { 0, 0 };
- struct timeval curtime;
-
- assert(pthread_cond_init(&cv, NULL) == 0);
-
- assert(pthread_mutex_init(&mutex) == 0);
-
- assert(pthread_mutex_lock(&mutex) == 0);
-
- assert(gettimeofday(&curtime, NULL) == 0);
-
- abstime.tv_sec = curtime.tv_sec + 5;
-
- assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT);
-
- assert(pthread_mutex_unlock(&mutex) == 0);
-
- assert(pthread_cond_destroy(&cv) == 0);
-
- return 0;
-}
-
+/*
+ * File: condvar1.c
+ *
+ * Test Synopsis:
+ * - Test timed wait on a CV.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * - Because the CV is never signaled, we expect the wait to time out.
+ *
+ * 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.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+pthread_cond_t cv;
+pthread_mutex_t mutex;
+
+int
+main()
+{
+ struct timespec abstime = { 0, 0 };
+#if defined(__MINGW32__)
+ struct timeb currSysTime;
+#else
+ struct _timeb currSysTime;
+#endif
+ const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+ assert(pthread_cond_init(&cv, NULL) == 0);
+
+ assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+ assert(pthread_mutex_lock(&mutex) == 0);
+
+ /* get current system time */
+ _ftime(&currSysTime);
+
+ abstime.tv_sec = currSysTime.time;
+ abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+ abstime.tv_sec += 5;
+
+ assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT);
+
+ assert(pthread_mutex_unlock(&mutex) == 0);
+
+ assert(pthread_cond_destroy(&cv) == 0);
+
+ return 0;
+}
+
diff --git a/tests/condvar3.c b/tests/condvar3.c
index 97a17cf..8dc56af 100644
--- a/tests/condvar3.c
+++ b/tests/condvar3.c
@@ -1,103 +1,109 @@
-/*
- * File: condvar1.c
- *
- * Test Synopsis:
- * - Test basic function of a CV
- *
- * Test Method (Validation or Falsification):
- * - Validation
- *
- * Requirements Tested:
- * -
- *
- * Features Tested:
- * -
- *
- * Cases Tested:
- * -
- *
- * Description:
- * - The primary thread takes the lock before creating any threads.
- * The secondary thread blocks on the lock allowing the primary
- * thread to enter the cv wait state which releases the lock.
- * The secondary thread then takes the lock and signals the waiting
- * primary thread.
- *
- * Environment:
- * -
- *
- * Input:
- * - None.
- *
- * Output:
- * - File name, Line number, and failed expression on failure.
- * - No output on success.
- *
- * Assumptions:
- * -
- *
- * Pass Criteria:
- * - pthread_cond_timedwait returns 0.
- * - Process returns zero exit status.
- *
- * Fail Criteria:
- * - pthread_cond_timedwait returns ETIMEDOUT.
- * - Process returns non-zero exit status.
- */
-
-#include "test.h"
-
-typedef struct cvthing_t_ cvthing_t;
-
-struct cvthing_t_ {
- pthread_cond_t notbusy;
- pthread_mutex_t lock;
-};
-
-static cvthing_t cvthing;
-
-static enum {
- NUMTHREADS = 2 /* Including the primary thread. */
-};
-
-void *
-mythread(void * arg)
-{
- assert(pthread_mutex_lock(&cvthing.lock) == 0);
-
- assert(pthread_cond_signal(&cvthing.notbusy) == 0);
-
- assert(pthread_mutex_unlock(&cvthing.lock) == 0);
-
- return 0;
-}
-
-int
-main()
-{
- pthread_t t[NUMTHREADS];
- struct timespec abstime = { 0, 0 };
- struct timeval curtime;
-
- assert((t[0] = pthread_self()) != NULL);
-
- assert(pthread_cond_init(&cvthing, NULL) == 0);
-
- assert(pthread_mutex_init(&cvthing.lock) == 0);
-
- assert(pthread_mutex_lock(&cvthing.lock) == 0);
-
- assert(gettimeofday(&curtime, NULL) == 0);
-
- abstime.tv_sec = curtime.tv_sec + 5;
-
- assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
-
- assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
-
- assert(pthread_mutex_unlock(&cvthing.lock) == 0);
-
- assert(pthread_cond_destroy(&cvthing) == 0);
-
- return 0;
-}
+/*
+ * File: condvar3.c
+ *
+ * Test Synopsis:
+ * - Test basic function of a CV
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * - The primary thread takes the lock before creating any threads.
+ * The secondary thread blocks on the lock allowing the primary
+ * thread to enter the cv wait state which releases the lock.
+ * The secondary thread then takes the lock and signals the waiting
+ * primary thread.
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns 0.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+pthread_cond_t cv;
+pthread_mutex_t mutex;
+
+enum {
+ NUMTHREADS = 2 /* Including the primary thread. */
+};
+
+void *
+mythread(void * arg)
+{
+ Sleep(1);
+
+ assert(pthread_mutex_lock(&mutex) == 0);
+
+ assert(pthread_cond_signal(&cv) == 0);
+
+ assert(pthread_mutex_unlock(&mutex) == 0);
+
+ return 0;
+}
+
+int
+main()
+{
+ pthread_t t[NUMTHREADS];
+ struct timespec abstime = { 0, 0 };
+#if defined(__MINGW32__)
+ struct timeb currSysTime;
+#else
+ struct _timeb currSysTime;
+#endif
+ const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+ assert((t[0] = pthread_self()) != NULL);
+
+ assert(pthread_cond_init(&cv, NULL) == 0);
+
+ assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+ assert(pthread_mutex_lock(&mutex) == 0);
+
+ /* get current system time */
+ _ftime(&currSysTime);
+
+ abstime.tv_sec = currSysTime.time;
+ abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+ assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
+
+ abstime.tv_sec += 5;
+
+ assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == 0);
+
+ assert(pthread_mutex_unlock(&mutex) == 0);
+
+ assert(pthread_cond_destroy(&cv) == 0);
+
+ return 0;
+}
diff --git a/tests/condvar4.c b/tests/condvar4.c
index 867746b..4c5fc38 100644
--- a/tests/condvar4.c
+++ b/tests/condvar4.c
@@ -1,106 +1,121 @@
-/*
- * File: condvar1.c
- *
- * Test Synopsis:
- * - Test PTHREAD_COND_INITIALIZER.
- *
- * Test Method (Validation or Falsification):
- * - Validation
- *
- * Requirements Tested:
- * -
- *
- * Features Tested:
- * -
- *
- * Cases Tested:
- * -
- *
- * Description:
- * - Test basic CV function but starting with a static initialised
- * CV.
- *
- * Environment:
- * -
- *
- * Input:
- * - None.
- *
- * Output:
- * - File name, Line number, and failed expression on failure.
- * - No output on success.
- *
- * Assumptions:
- * -
- *
- * Pass Criteria:
- * - pthread_cond_timedwait returns 0.
- * - Process returns zero exit status.
- *
- * Fail Criteria:
- * - pthread_cond_timedwait returns ETIMEDOUT.
- * - Process returns non-zero exit status.
- */
-
-#include "test.h"
-
-typedef struct cvthing_t_ cvthing_t;
-
-struct cvthing_t_ {
- pthread_cond_t notbusy;
- pthread_mutex_t lock;
- int busy;
- int count;
-};
-
-static cvthing_t cvthing = {
- PTHREAD_MUTEX_INITIALIZER,
- PTHREAD_COND_INITIALIZER,
-};
-
-static enum {
- NUMTHREADS = 2
-};
-
-void *
-mythread(void * arg)
-{
- assert(pthread_mutex_lock(&cvthing.lock) == 0);
-
- assert(pthread_cond_signal(&cvthing.notbusy) == 0);
-
- assert(pthread_mutex_unlock(&cvthing.lock) == 0);
-
- return 0;
-}
-
-int
-main()
-{
- pthread_t t[NUMTHREADS];
- int result[NUMTHREADS];
- struct timespec abstime = { 0, 0 };
- struct timeval curtime;
-
- assert((t[0] = pthread_self()) != NULL);
-
- assert(pthread_mutex_lock(&cvthing.lock) == 0);
-
- gettimeofday(&curtime, NULL);
- abstime.tv_sec = curtime.tv_sec + 5;
-
- assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT);
-
- assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
-
- gettimeofday(&curtime, NULL);
- abstime.tv_sec = curtime.tv_sec + 10;
-
- assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
-
- assert(pthread_mutex_unlock(&cvthing.lock) == 0);
-
- assert(pthread_cond_destroy(&cvthing) == 0);
-
- return 0;
-}
+/*
+ * File: condvar1.c
+ *
+ * Test Synopsis:
+ * - Test PTHREAD_COND_INITIALIZER.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * - Test basic CV function but starting with a static initialised
+ * CV.
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns 0.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+typedef struct cvthing_t_ cvthing_t;
+
+struct cvthing_t_ {
+ pthread_cond_t notbusy;
+ pthread_mutex_t lock;
+};
+
+static cvthing_t cvthing = {
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_COND_INITIALIZER,
+};
+
+enum {
+ NUMTHREADS = 2
+};
+
+void *
+mythread(void * arg)
+{
+ assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+ assert(pthread_cond_signal(&cvthing.notbusy) == 0);
+
+ assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+ return 0;
+}
+
+int
+main()
+{
+ pthread_t t[NUMTHREADS];
+ struct timespec abstime = { 0, 0 };
+#if defined(__MINGW32__)
+ struct timeb currSysTime;
+#else
+ struct _timeb currSysTime;
+#endif
+ const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+ assert(cvthing.notbusy.staticinit == 1);
+ assert(cvthing.notbusy.valid == 1);
+
+ assert((t[0] = pthread_self()) != NULL);
+
+ assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+ /* get current system time */
+ _ftime(&currSysTime);
+
+ abstime.tv_sec = currSysTime.time;
+ abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+ abstime.tv_sec += 5;
+
+ assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT);
+
+ assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
+
+ _ftime(&currSysTime);
+
+ abstime.tv_sec = currSysTime.time;
+ abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+ abstime.tv_sec += 5;
+
+ assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
+
+ assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+ assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
+
+ return 0;
+}