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;
 +}
 | 
