diff options
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | condvar.c | 210 | ||||
-rw-r--r-- | global.c | 6 | ||||
-rw-r--r-- | implement.h | 1 | ||||
-rw-r--r-- | misc.c | 52 | ||||
-rw-r--r-- | mutex.c | 2 | ||||
-rw-r--r-- | private.c | 6 | ||||
-rw-r--r-- | pthread.h | 53 | ||||
-rw-r--r-- | semaphore.c | 10 | ||||
-rw-r--r-- | tests/Makefile | 139 | ||||
-rw-r--r-- | tests/condvar2.c | 156 | ||||
-rw-r--r-- | tests/condvar3.c | 212 | ||||
-rw-r--r-- | tests/condvar4.c | 227 |
13 files changed, 658 insertions, 462 deletions
@@ -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 @@ -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) { @@ -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> @@ -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: @@ -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); } @@ -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; } @@ -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;
+}
|