diff options
| author | rpj <rpj> | 1999-03-11 15:06:20 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 1999-03-11 15:06:20 +0000 | 
| commit | b14e60afab45a7bc5eff231f408505a1bec6b436 (patch) | |
| tree | 4f9980eea7b03957476af05736a2c8364027d9c3 | |
| parent | 52f7c3f5ef6d9b70ec385fb390bf27962e68ee3d (diff) | |
Thu Mar 11 09:01:48 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
        * pthread.h (pthread_mutex_t): revert to (pthread_mutex_t *);
        define a value to serve as PTHREAD_MUTEX_INITIALIZER.
        (pthread_mutex_t_): remove staticinit and valid elements.
        (pthread_cond_t): revert to (pthread_cond_t_ *);
        define a value to serve as PTHREAD_COND_INITIALIZER.
        (pthread_cond_t_): remove staticinit and valid elements.
        * mutex.c (pthread_mutex_t args): adjust indirection of references.
        (all functions): check for PTHREAD_MUTEX_INITIALIZER value;
        check for NULL (invalid).
        * condvar.c (pthread_cond_t args): adjust indirection of references.
        (all functions): check for PTHREAD_COND_INITIALIZER value;
        check for NULL (invalid).
Wed Mar 10 17:18:12 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
        * misc.c (CancelableWait): Undo changes from Mar 8 and 7.
tests/ChangeLog
Fri Mar 12 08:34:15 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
        * eyal1.c (main): Fix trylock loop; was not waiting for thread to lock
        the "started" mutex.
| -rw-r--r-- | ChangeLog | 21 | ||||
| -rw-r--r-- | FAQ | 14 | ||||
| -rw-r--r-- | condvar.c | 148 | ||||
| -rw-r--r-- | misc.c | 52 | ||||
| -rw-r--r-- | mutex.c | 133 | ||||
| -rw-r--r-- | pthread.h | 27 | ||||
| -rw-r--r-- | tests/ChangeLog | 5 | ||||
| -rw-r--r-- | tests/condvar3.c | 218 | ||||
| -rw-r--r-- | tests/condvar4.c | 239 | ||||
| -rw-r--r-- | tests/eyal1.c | 394 | ||||
| -rw-r--r-- | tests/mutex2.c | 6 | ||||
| -rw-r--r-- | tests/tsd1.c | 4 | 
12 files changed, 657 insertions, 604 deletions
| @@ -1,3 +1,24 @@ +Thu Mar 11 09:01:48 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* pthread.h (pthread_mutex_t): revert to (pthread_mutex_t *); +	define a value to serve as PTHREAD_MUTEX_INITIALIZER. +	(pthread_mutex_t_): remove staticinit and valid elements. +	(pthread_cond_t): revert to (pthread_cond_t_ *); +	define a value to serve as PTHREAD_COND_INITIALIZER. +	(pthread_cond_t_): remove staticinit and valid elements. + +	* mutex.c (pthread_mutex_t args): adjust indirection of references. +	(all functions): check for PTHREAD_MUTEX_INITIALIZER value; +	check for NULL (invalid). + +	* condvar.c (pthread_cond_t args): adjust indirection of references. +	(all functions): check for PTHREAD_COND_INITIALIZER value; +	check for NULL (invalid). + +Wed Mar 10 17:18:12 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* misc.c (CancelableWait): Undo changes from Mar 8 and 7. +  Mon Mar  8 11:18:59 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* misc.c (CancelableWait): Ensure cancelEvent handle is the lowest @@ -5,22 +5,24 @@  INDEX  ----- -Q 1	How do I get pthreads-win32 to link under Cygwin or Mingw32? +Q 1	Should I use Cygwin or Mingw32 as a development environment?  Q 2	Now that pthreads-win32 builds under Mingw32, why do I get  	memory access violations?  ============================================================================= -Q 1	How do I get pthreads-win32 to link under Cygwin or Mingw32? +Q 1	Should I use Cygwin or Mingw32 as a development environment?  ---  A 1  --- -The following email from Anders Norlander explains how to solve this -problem. I think the proviso is that the DLL and your application should -both be built with the same development environment (cygwin, mingw, -or MSVC etc). +Important: see Q2 also. + +I short, use Mingw32 with the MSVCRT library to build applications that use +the DLL. You cannot build the library itself with either yet because the +library uses C++ EH which is not thread-safe in egcs yet. Use MSVC or grab +the pre-build DLL etc.  Date: Mon, 07 Dec 1998 15:11:37 +0100  From: Anders Norlander <anorland@hem2.passagen.se> @@ -19,7 +19,7 @@ _cond_check_need_init(pthread_cond_t *cond)    /*     * The following guarded test is specifically for statically -   * initialised condition variables (via PTHREAD_COND_INITIALIZER). +   * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER).     *     * Note that by not providing this synchronisation we risk     * introducing race conditions into applications which are @@ -31,38 +31,23 @@ _cond_check_need_init(pthread_cond_t *cond)     * 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). +   * We got here possibly under race +   * conditions. Check again inside the critical section.     * 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) +  if (*cond == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT)      {        result = pthread_cond_init(cond, NULL);      } @@ -342,20 +327,13 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)        */  {    int result = EAGAIN; +  pthread_cond_t cv;    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))      { @@ -368,34 +346,37 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)        goto FAIL0;      } -  cond->waiters = 0; -  cond->wasBroadcast = FALSE; +  cv = (pthread_cond_t) calloc (1, sizeof (*cv)); -  if (_pthread_sem_init (&(cond->sema), 0, 0) != 0) +  if (cv == NULL)      { +      result = ENOMEM;        goto FAIL0;      } -  if (pthread_mutex_init (&(cond->waitersLock), NULL) != 0) + +  cv->waiters = 0; +  cv->wasBroadcast = FALSE; + +  if (_pthread_sem_init (&(cv->sema), 0, 0) != 0) +    { +      goto FAIL0; +    } +  if (pthread_mutex_init (&(cv->waitersLock), NULL) != 0)      {        goto FAIL1;      } -  cond->waitersDone = CreateEvent ( -                                  0, -                                  (int) FALSE,  /* manualReset  */ -                                  (int) FALSE,  /* setSignaled  */ -                                  NULL); +  cv->waitersDone = CreateEvent ( +				 0, +				 (int) FALSE,  /* manualReset  */ +				 (int) FALSE,  /* setSignaled  */ +				 NULL); -  if (cond->waitersDone == NULL) +  if (cv->waitersDone == NULL)      {        goto FAIL2;      } -  cond->staticinit = 0; - -  /* Mark as valid. */ -  cond->valid = 1; -    result = 0;    goto DONE; @@ -406,13 +387,15 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)     * -------------     */  FAIL2: -  (void) pthread_mutex_destroy (&(cond->waitersLock)); +  (void) pthread_mutex_destroy (&(cv->waitersLock));  FAIL1: -  (void) _pthread_sem_destroy (&(cond->sema)); +  (void) _pthread_sem_destroy (&(cv->sema));  FAIL0:  DONE: +  *cond = cv; +    return (result);  }                               /* pthread_cond_init */ @@ -447,25 +430,30 @@ pthread_cond_destroy (pthread_cond_t * cond)        */  {    int result = 0; +  pthread_cond_t cv;    /*     * Assuming any race condition here is harmless.     */ -  if (cond == NULL || cond->valid == 0 || cond->staticinit == 1) +  if (cond == NULL  +      || *cond == NULL)      {        return EINVAL;      } -  if (cond->waiters > 0) +  cv = *cond; + +  if (cv->waiters > 0)      {        return EBUSY;      } -  (void) _pthread_sem_destroy (&(cond->sema)); -  (void) pthread_mutex_destroy (&(cond->waitersLock)); -  (void) CloseHandle (cond->waitersDone); -       -  cond->valid = 0; +  (void) _pthread_sem_destroy (&(cv->sema)); +  (void) pthread_mutex_destroy (&(cv->waitersLock)); +  (void) CloseHandle (cv->waitersDone); + +  free(cv); +  *cond = NULL;    return (result);  } @@ -478,14 +466,22 @@ cond_timedwait (pthread_cond_t * cond,    int result = 0;    int internal_result = 0;    int lastWaiter = FALSE; +  pthread_cond_t cv; + +  if (cond == NULL || *cond == NULL) +    { +      return EINVAL; +    } + +  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' +   * to initialise a static condition variable. We check     * again inside the guarded section of _cond_check_need_init()     * to avoid race conditions.     */ -  if (cond->staticinit == 1) +  if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT)      {        result = _cond_check_need_init(cond);      } @@ -493,7 +489,7 @@ cond_timedwait (pthread_cond_t * cond,    /*     * OK to increment  cond->waiters because the caller locked 'mutex'     */ -  cond->waiters++; +  cv->waiters++;    /*     * We keep the lock held just long enough to increment the count of @@ -518,23 +514,23 @@ cond_timedwait (pthread_cond_t * cond,         */        pthread_cleanup_push (pthread_mutex_lock, mutex); -      result = _pthread_sem_timedwait (&(cond->sema), abstime); +      result = _pthread_sem_timedwait (&(cv->sema), abstime);        pthread_cleanup_pop (0);      } -  if ((internal_result = pthread_mutex_lock (&(cond->waitersLock))) == 0) +  if ((internal_result = pthread_mutex_lock (&(cv->waitersLock))) == 0)      {        /*         * By making the waiter responsible for decrementing         * its count we don't have to worry about having an internal         * mutex.         */ -      cond->waiters--; +      cv->waiters--; -      lastWaiter = cond->wasBroadcast && (cond->waiters == 0); +      lastWaiter = cv->wasBroadcast && (cv->waiters == 0); -      internal_result = pthread_mutex_unlock (&(cond->waitersLock)); +      internal_result = pthread_mutex_unlock (&(cv->waitersLock));      }    if (result == 0 && internal_result == 0) @@ -545,7 +541,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 (cond->waitersDone)) +          if (!SetEvent (cv->waitersDone))              {                result = EINVAL;              } @@ -727,16 +723,19 @@ pthread_cond_signal (pthread_cond_t * cond)        */  {    int result = 0; +  pthread_cond_t cv; -  if (cond == NULL || cond->valid == 0) +  if (cond == NULL || *cond == NULL)      {        return EINVAL;      } +  cv = *cond; +    /*     * No-op if the CV is static and hasn't been initialised yet.     */ -  if (cond->staticinit == 1) +  if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT)      {        return 0;      } @@ -744,9 +743,9 @@ pthread_cond_signal (pthread_cond_t * cond)    /*     * If there aren't any waiters, then this is a no-op.     */ -  if (cond->waiters > 0) +  if (cv->waiters > 0)      { -      result = _pthread_sem_post (&(cond->sema)); +      result = _pthread_sem_post (&(cv->sema));      }    return (result); @@ -793,18 +792,21 @@ pthread_cond_broadcast (pthread_cond_t * cond)  {    int result = 0;    int i; +  pthread_cond_t cv; -  if (cond == NULL || cond->valid == 0) +  if (cond == NULL || *cond == NULL)      {        return EINVAL;      } -  cond->wasBroadcast = TRUE; +  cv = *cond; + +  cv->wasBroadcast = TRUE;    /*     * No-op if the CV is static and hasn't been initialised yet.     */ -  if (cond->staticinit == 1) +  if (cv == (pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT)      {        return 0;      } @@ -812,24 +814,21 @@ pthread_cond_broadcast (pthread_cond_t * cond)    /*     * Wake up all waiters     */ -  for (i = cond->waiters; i > 0 && result == 0; i--) +  for (i = cv->waiters; i > 0 && result == 0; i--)      { - -      result = _pthread_sem_post (&(cond->sema)); +      result = _pthread_sem_post (&(cv->sema));      } -  if (cond->waiters > 0 && result == 0) +  if (cv->waiters > 0 && result == 0)      {        /*         * Wait for all the awakened threads to acquire their part of         * the counting semaphore         */ -      if (WaitForSingleObject (cond->waitersDone, INFINITE) != +      if (WaitForSingleObject (cv->waitersDone, INFINITE) !=            WAIT_OBJECT_0)          { -            result = 0; -          }        else          { @@ -839,6 +838,7 @@ pthread_cond_broadcast (pthread_cond_t * cond)      }    return (result); +  }  /* </JEB> */ @@ -213,12 +213,8 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)    DWORD nHandles = 1;    DWORD status; -  /* -   * 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. -   */ +  handles[0] = waitHandle; +    if ((self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey))         != NULL)      { @@ -228,14 +224,16 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)        if (self->cancelState == PTHREAD_CANCEL_ENABLE)          { -          if ((handles[0] = self->cancelEvent) != NULL) +          if ((handles[1] = self->cancelEvent) != NULL)              {                nHandles++;              }          }      } - -  handles[nHandles - 1] = waitHandle; +  else +    { +      handles[1] = NULL; +    }    status = WaitForMultipleObjects (                                      nHandles, @@ -243,36 +241,41 @@ 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 && status <= WAIT_ABANDONED_0 + nHandles - 1) +  else if (status == WAIT_ABANDONED_0)      { -      /* -       * The waitHandle was a mutex object that was abandoned. -       */        result = EINVAL;      }    else      {        /* -       * Either got the object or the cancel event -       * was signaled, or both in which case the cancel -       * event will be acted on. +       * Either got the mutex or the cancel event +       * was signaled         */ -      switch (status - WAIT_OBJECT_0 + 2 - nHandles) +      switch (status - WAIT_OBJECT_0)          {          case 0:            /* -           * Got cancel request. +           * Got the mutex +           */ +          result = 0; +          break; + +        case 1: +          /* +           * Got cancel request             */ -          ResetEvent (handles[0]); +          ResetEvent (handles[1]);            if (self != NULL && !self->implicit)              { @@ -304,15 +307,8 @@ CancelableWait (HANDLE waitHandle, DWORD timeout)  #endif /* _MSC_VER */              } -          /* Should never get to here. */ -          result = EINVAL; -          break; - -        case 1: -          /* -           * Got the object. -           */ -          result = 0; +         /* Should never get to here. */ +         result = EINVAL;            break;          default: @@ -30,38 +30,24 @@ _mutex_check_need_init(pthread_mutex_t *mutex)     * 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-mutex state independently: -   *   - mutex staticinit (true iff mutex is static and still -   *                        needs to be initialised) -   *   - mutex valid (false iff mutex has been destroyed) -   * -   * For example, in this implementation a mutex initialised by -   * PTHREAD_MUTEX_INITIALIZER will be 'valid' but uninitialised until -   * the thread attempts to lock it. It can also be destroyed (made invalid) -   * before ever being locked.     */    EnterCriticalSection(&_pthread_mutex_test_init_lock);    /* -   * We got here because staticinit tested true, possibly under race -   * conditions. Check staticinit again inside the critical section +   * We got here possibly under race +   * conditions. Check again inside the critical section     * and only initialise if the mutex is valid (not been destroyed).     * If a static mutex has been destroyed, the application can     * re-initialise it only by calling pthread_mutex_init()     * explicitly.     */ -  if (mutex->staticinit && mutex->valid) +  if (*mutex == (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT)      {        result = pthread_mutex_init(mutex, NULL);      } @@ -75,22 +61,25 @@ int  pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)  {    int result = 0; +  pthread_mutex_t mx;    if (mutex == NULL)      {        return EINVAL;      } -  mutex->mutex = 0; +  mx = *mutex; -  /*  -   * Assuming any race condition here is harmless. -   */ -  if (mutex->valid && !mutex->staticinit) +  mx = (pthread_mutex_t) calloc(1, sizeof(*mx)); + +  if (mx == NULL)      { -      return EBUSY; +      result = ENOMEM; +      goto FAIL0;      } +  mx->mutex = 0; +    if (attr != NULL        && *attr != NULL        && (*attr)->pshared == PTHREAD_PROCESS_SHARED @@ -108,11 +97,11 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)  #error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. -      mutex->mutex = CreateMutex ( +      mx->mutex = CreateMutex (  				  NULL,  				  FALSE,  				  ????); -      result = (mutex->mutex == 0) ? EAGAIN : 0; +      result = (mx->mutex == 0) ? EAGAIN : 0;  #else @@ -131,7 +120,7 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)  	  /*   	   * Create a critical section.   	   */ -	  InitializeCriticalSection(&mutex->cs); +	  InitializeCriticalSection(&mx->cs);  	}        else  	{ @@ -139,20 +128,21 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)  	   * Create a mutex that can only be used within the  	   * current process  	   */ -	  mutex->mutex = CreateMutex (NULL, -				      FALSE, -				      NULL); -	  result = (mutex->mutex == 0) ? EAGAIN : 0; +	  mx->mutex = CreateMutex (NULL, +				   FALSE, +				   NULL); + +	  if (mx->mutex == 0) +	    { +	      result = EAGAIN; +	      mx = NULL; +	      goto FAIL0; +	    }  	}      } -  if (result == 0) -    { -      mutex->staticinit = 0; - -      /* Mark as valid. */ -      mutex->valid = 1; -    } +FAIL0: +  *mutex = mx;    return(result);  } @@ -161,33 +151,35 @@ int  pthread_mutex_destroy(pthread_mutex_t *mutex)  {    int result = 0; +  pthread_mutex_t mx; -  if (mutex == NULL) +  if (mutex == NULL +      || *mutex == NULL)      {        return EINVAL;      } +  mx = *mutex; +    /*     * Check to see if we have something to delete.     */ -  if (!mutex->staticinit) +  if (mx != (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT)      { -      if (mutex->mutex == 0) +      if (mx->mutex == 0)  	{ -	  DeleteCriticalSection(&mutex->cs); +	  DeleteCriticalSection(&mx->cs);  	}        else  	{ -	  result = (CloseHandle (mutex->mutex) ? 0 : EINVAL); +	  result = (CloseHandle (mx->mutex) ? 0 : EINVAL);  	}      }    if (result == 0)      { -      mutex->mutex = 0; - -      /* Mark as invalid. */ -      mutex->valid = 0; +      mx->mutex = 0; +      *mutex = NULL;      }    return(result); @@ -444,27 +436,35 @@ int  pthread_mutex_lock(pthread_mutex_t *mutex)  {    int result = 0; +  pthread_mutex_t mx; + +  if (mutex == NULL || *mutex == NULL) +    { +      return EINVAL; +    }    /*     * We do a quick check to see if we need to do more work -   * to initialise a static mutex. We check 'staticinit' +   * to initialise a static mutex. We check     * again inside the guarded section of _mutex_check_need_init()     * to avoid race conditions.     */ -  if (mutex->staticinit == 1) +  if (*mutex == (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT)      {        result = _mutex_check_need_init(mutex);      } +  mx = *mutex; +    if (result == 0)      { -      if (mutex->mutex == 0) +      if (mx->mutex == 0)  	{ -	  EnterCriticalSection(&mutex->cs); +	  EnterCriticalSection(&mx->cs);  	}        else  	{ -	  result = (WaitForSingleObject(mutex->mutex, INFINITE)  +	  result = (WaitForSingleObject(mx->mutex, INFINITE)   		    == WAIT_OBJECT_0)  	    ? 0  	    : EINVAL; @@ -478,21 +478,29 @@ int  pthread_mutex_unlock(pthread_mutex_t *mutex)  {    int result = 0; +  pthread_mutex_t mx; + +  if (mutex == NULL || *mutex == NULL) +    { +      return EINVAL; +    } + +  mx = *mutex;    /*      * If the thread calling us holds the mutex then there is no     * race condition. If another thread holds the     * lock then we shouldn't be in here.     */ -  if (!mutex->staticinit && mutex->valid) +  if (mx != (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT)      { -      if (mutex->mutex == 0) +      if (mx->mutex == 0)  	{ -	  LeaveCriticalSection(&mutex->cs); +	  LeaveCriticalSection(&mx->cs);  	}        else  	{ -	  result = (ReleaseMutex (mutex->mutex) ? 0 : EINVAL); +	  result = (ReleaseMutex (mx->mutex) ? 0 : EINVAL);  	}      }    else @@ -507,28 +515,31 @@ int  pthread_mutex_trylock(pthread_mutex_t *mutex)  {    int result = 0; +  pthread_mutex_t mx; -  if (mutex == NULL) +  if (mutex == NULL || *mutex == NULL)      {        return EINVAL;      }    /*     * We do a quick check to see if we need to do more work -   * to initialise a static mutex. We check 'staticinit' +   * to initialise a static mutex. We check     * again inside the guarded section of _mutex_check_need_init()     * to avoid race conditions.     */ -  if (mutex->staticinit) +  if (*mutex == (pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT)      {        result = _mutex_check_need_init(mutex);      } +  mx = *mutex; +    if (result == 0)      { -      if (mutex->mutex == 0) +      if (mx->mutex == 0)  	{ -	  if ((*_pthread_try_enter_critical_section)(&mutex->cs) != TRUE) +	  if ((*_pthread_try_enter_critical_section)(&mx->cs) != TRUE)  	    {  	      result = EBUSY;  	    } @@ -537,7 +548,7 @@ pthread_mutex_trylock(pthread_mutex_t *mutex)  	{  	  DWORD status; -	  status = WaitForSingleObject (mutex->mutex, 0); +	  status = WaitForSingleObject (mx->mutex, 0);  	  if (status != WAIT_OBJECT_0)  	    { @@ -419,9 +419,9 @@ extern "C"    typedef struct pthread_attr_t_ *pthread_attr_t;    typedef struct pthread_once_t_ pthread_once_t;    typedef struct pthread_key_t_ *pthread_key_t; -  typedef struct pthread_mutex_t_ pthread_mutex_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; @@ -567,16 +567,19 @@ struct pthread_attr_t_ {  /*   * ====================   * ==================== - * Mutex + * Mutexes and Condition Variables   * ====================   * ====================   */ -#define PTHREAD_MUTEX_INITIALIZER { 1, 1 /* Remaining are all 0 */ } +enum { +  _PTHREAD_OBJECT_INVALID = 0,  /* NULL */ +  _PTHREAD_OBJECT_AUTO_INIT +}; + +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT)  struct pthread_mutex_t_ { -  int staticinit;                     /* Needs implicit init if 1. */ -  int valid;                          /* Not destroyed if 1. */    HANDLE mutex;    CRITICAL_SECTION cs;  }; @@ -596,21 +599,11 @@ struct pthread_key_t_ {  }; -/* - * ==================== - * ==================== - * Condition Variable - * ==================== - * ==================== - */ - -#define PTHREAD_COND_INITIALIZER { 1, 1 /* Remaining are all 0 */ } +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT)  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/tests/ChangeLog b/tests/ChangeLog index aef418f..0304802 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,8 @@ +Fri Mar 12 08:34:15 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* eyal1.c (main): Fix trylock loop; was not waiting for thread to lock +	the "started" mutex. +  Sun Mar  7 10:41:52 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* Makefile (condvar3, condvar4): Add tests. diff --git a/tests/condvar3.c b/tests/condvar3.c index 8dc56af..27223ab 100644 --- a/tests/condvar3.c +++ b/tests/condvar3.c @@ -1,109 +1,109 @@ -/*
 - * 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;
 -}
 +/* + * 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 4c5fc38..f93db27 100644 --- a/tests/condvar4.c +++ b/tests/condvar4.c @@ -1,121 +1,118 @@ -/*
 - * 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;
 -}
 +/* + * 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((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; +} diff --git a/tests/eyal1.c b/tests/eyal1.c index 4345452..533822d 100644 --- a/tests/eyal1.c +++ b/tests/eyal1.c @@ -49,15 +49,16 @@  #include <math.h>  struct thread_control { -	int		id; -	pthread_t	thread;		/* thread id */ -	pthread_mutex_t	mutex_start; -	pthread_mutex_t	mutex_started; -	pthread_mutex_t	mutex_end; -	pthread_mutex_t	mutex_ended; -	long		work;		/* work done */ -	int		stat;		/* pthread_init status */ +  int		id; +  pthread_t	thread;		/* thread id */ +  pthread_mutex_t	mutex_start; +  pthread_mutex_t	mutex_started; +  pthread_mutex_t	mutex_end; +  pthread_mutex_t	mutex_ended; +  long		work;		/* work done */ +  int		stat;		/* pthread_init status */  }; +  typedef struct thread_control	TC;  static TC		*tcs = NULL; @@ -70,229 +71,250 @@ static int		todo = -1;  static pthread_mutex_t	mutex_todo = PTHREAD_MUTEX_INITIALIZER;  static pthread_mutex_t	mutex_stdout = PTHREAD_MUTEX_INITIALIZER; -/*static pthread_attr_t    pthread_attr_default;*/ -  static void  die (int ret)  { -	if (NULL != tcs) { -		free (tcs); -		tcs = NULL; -	} - -	if (ret) -		exit (ret); +  if (NULL != tcs) +    { +      free (tcs); +      tcs = NULL; +    } + +  if (ret) +    exit (ret);  }  static void  waste_time (int n)  { -	int		i; -	double		f; +  int		i; +  double		f; -	f = rand (); +  f = rand (); -	for (i = n*100; i > 0; --i) { -		f = sqrt (f) * f + 10000.0; -	} +  for (i = n*100; i > 0; --i) +    { +      f = sqrt (f) * f + 10000.0; +    }  }  static int  do_work_unit (int who, int n)  { -	int		i; -	static int	nchars = 0; +  int		i; +  static int	nchars = 0; -	if (quiet) -		i = 0; -	else { -/* get lock on stdout -*/ -		assert(pthread_mutex_lock (&mutex_stdout) == 0); +  if (quiet) +    i = 0; +  else { +    /* +     * get lock on stdout +     */ +    assert(pthread_mutex_lock (&mutex_stdout) == 0); -/* do our job -*/ -		i = printf ("%c", -			"0123456789abcdefghijklmnopqrstuvwxyz"[who]); -		if (!(++nchars % 50)) -			printf ("\n"); -		fflush (stdout); +    /* +     * do our job +     */ +    i = printf ("%c", "0123456789abcdefghijklmnopqrstuvwxyz"[who]); -/* release lock on stdout -*/ -		assert(pthread_mutex_unlock (&mutex_stdout) == 0); -	} +    if (!(++nchars % 50)) +      printf ("\n"); -	n = rand () % 10000;	/* ignore incoming 'n' */ -	waste_time (n); +    fflush (stdout); -	return (n); +    /* +     * release lock on stdout +     */ +    assert(pthread_mutex_unlock (&mutex_stdout) == 0); +  } + +  n = rand () % 10000;	/* ignore incoming 'n' */ +  waste_time (n); + +  return (n);  }  static int  print_server (void *ptr)  { -	int		mywork; -	int		n; -	TC		*tc = (TC *)ptr; - -	assert(pthread_mutex_lock (&tc->mutex_started) == 0); - -	for (;;) { -		assert(pthread_mutex_lock (&tc->mutex_start) == 0); -		assert(pthread_mutex_unlock (&tc->mutex_start) == 0); -		assert(pthread_mutex_lock (&tc->mutex_ended) == 0); -		assert(pthread_mutex_unlock (&tc->mutex_started) == 0); +  int		mywork; +  int		n; +  TC		*tc = (TC *)ptr; + +  assert(pthread_mutex_lock (&tc->mutex_started) == 0); + +  for (;;) +    { +      assert(pthread_mutex_lock (&tc->mutex_start) == 0); +      assert(pthread_mutex_unlock (&tc->mutex_start) == 0); +      assert(pthread_mutex_lock (&tc->mutex_ended) == 0); +      assert(pthread_mutex_unlock (&tc->mutex_started) == 0); + +      for (;;) +	{ + +	  /* +	   * get lock on todo list +	   */ +	  assert(pthread_mutex_lock (&mutex_todo) == 0); + +	  mywork = todo; +	  if (todo >= 0) +	    { +	      ++todo; +	      if (todo >= nwork) +		todo = -1; +	    } +	  assert(pthread_mutex_unlock (&mutex_todo) == 0); + +	  if (mywork < 0) +	    break; + +	  assert((n = do_work_unit (tc->id, mywork)) >= 0); +	  tc->work += n; +	} -		for (;;) { +      assert(pthread_mutex_lock (&tc->mutex_end) == 0); +      assert(pthread_mutex_unlock (&tc->mutex_end) == 0); +      assert(pthread_mutex_lock (&tc->mutex_started) == 0); +      assert(pthread_mutex_unlock (&tc->mutex_ended) == 0); -/* get lock on todo list -*/ -			assert(pthread_mutex_lock (&mutex_todo) == 0); - -			mywork = todo; -			if (todo >= 0) { -				++todo; -				if (todo >= nwork) -					todo = -1; -			} -			assert(pthread_mutex_unlock (&mutex_todo) == 0); - -			if (mywork < 0) -				break; - -			assert((n = do_work_unit (tc->id, mywork)) >= 0); -			tc->work += n; -		} - -		assert(pthread_mutex_lock (&tc->mutex_end) == 0); -		assert(pthread_mutex_unlock (&tc->mutex_end) == 0); -		assert(pthread_mutex_lock (&tc->mutex_started) == 0); -		assert(pthread_mutex_unlock (&tc->mutex_ended) == 0); - -		if (-2 == mywork) -			break; -	} +      if (-2 == mywork) +	break; +    } -	assert(pthread_mutex_unlock (&tc->mutex_started) == 0); +  assert(pthread_mutex_unlock (&tc->mutex_started) == 0); -	return (0); +  return (0);  }  static void  dosync (void)  { -	int		i; - -	for (i = 0; i < nthreads; ++i) { -		assert(pthread_mutex_lock (&tcs[i].mutex_end) == 0); -		assert(pthread_mutex_unlock (&tcs[i].mutex_start) == 0); -		assert(pthread_mutex_lock (&tcs[i].mutex_started) == 0); -		assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0); -	} - -/* Now threads do their work -*/ -	for (i = 0; i < nthreads; ++i) { -		assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0); -		assert(pthread_mutex_unlock (&tcs[i].mutex_end) == 0); -		assert(pthread_mutex_lock (&tcs[i].mutex_ended) == 0); -		assert(pthread_mutex_unlock (&tcs[i].mutex_ended) == 0); -	} +  int		i; + +  for (i = 0; i < nthreads; ++i) +    { +      assert(pthread_mutex_lock (&tcs[i].mutex_end) == 0); +      assert(pthread_mutex_unlock (&tcs[i].mutex_start) == 0); +      assert(pthread_mutex_lock (&tcs[i].mutex_started) == 0); +      assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0); +    } + +  /* +   * Now threads do their work +   */ +  for (i = 0; i < nthreads; ++i) +    { +      assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0); +      assert(pthread_mutex_unlock (&tcs[i].mutex_end) == 0); +      assert(pthread_mutex_lock (&tcs[i].mutex_ended) == 0); +      assert(pthread_mutex_unlock (&tcs[i].mutex_ended) == 0); +    }  }  static void  dowork (void)  { -	todo = 0; -	dosync(); +  todo = 0; +  dosync(); -	todo = 0; -	dosync(); +  todo = 0; +  dosync();  }  int  main (int argc, char *argv[])  { -	int		i; - -	assert(NULL != (tcs = calloc (nthreads, sizeof (*tcs)))); - -/* Launch threads -*/ -	for (i = 0; i < nthreads; ++i) { -		tcs[i].id = i; - -		assert(pthread_mutex_init (&tcs[i].mutex_start, NULL) == 0); -		assert(pthread_mutex_init (&tcs[i].mutex_started, NULL) == 0); -		assert(pthread_mutex_init (&tcs[i].mutex_end, NULL) == 0); -		assert(pthread_mutex_init (&tcs[i].mutex_ended, NULL) == 0); - -		tcs[i].work = 0; - -		assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0); -		assert((tcs[i].stat =  -                    pthread_create (&tcs[i].thread, -			                  NULL, -			                  (void*)&print_server, (void *)&tcs[i]) -                    ) == 0); - -/* Wait for thread initialisation -*/ -		while (1) -              { -                int trylock; - -                trylock = pthread_mutex_trylock(&tcs[i].mutex_started); -                assert(trylock == 0 || trylock == EBUSY); - -                if (trylock == 0) -                  { -			  assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0); -                    break; -                  } -               } -	} - -	dowork (); - -/* Terminate threads -*/ -	todo = -2;	/* please terminate */ -	dosync(); - -	for (i = 0; i < nthreads; ++i) { -		if (0 == tcs[i].stat) -			assert(pthread_join (tcs[i].thread, NULL) == 0); -	} - -/* destroy locks -*/ -	assert(pthread_mutex_destroy (&mutex_stdout) == 0); -	assert(pthread_mutex_destroy (&mutex_todo) == 0); - -/* Cleanup -*/ -	printf ("\n"); - -/* Show results -*/ -	for (i = 0; i < nthreads; ++i) { -		printf ("%2d ", i); -		if (0 == tcs[i].stat) -			printf ("%10ld\n", tcs[i].work); -		else -			printf ("failed %d\n", tcs[i].stat); - -		assert(pthread_mutex_destroy (&tcs[i].mutex_start) == 0); -		assert(pthread_mutex_destroy (&tcs[i].mutex_started) == 0); -		assert(pthread_mutex_destroy (&tcs[i].mutex_end) == 0); -		assert(pthread_mutex_destroy (&tcs[i].mutex_ended) == 0); -	} - -	die (0); - -	return (0); +  int		i; + +  assert(NULL != (tcs = calloc (nthreads, sizeof (*tcs)))); + +  /*  +   * Launch threads +   */ +  for (i = 0; i < nthreads; ++i) +    { +      tcs[i].id = i; + +      assert(pthread_mutex_init (&tcs[i].mutex_start, NULL) == 0); +      assert(pthread_mutex_init (&tcs[i].mutex_started, NULL) == 0); +      assert(pthread_mutex_init (&tcs[i].mutex_end, NULL) == 0); +      assert(pthread_mutex_init (&tcs[i].mutex_ended, NULL) == 0); + +      tcs[i].work = 0; + +      assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0); +      assert((tcs[i].stat =  +	      pthread_create (&tcs[i].thread, +			      NULL, +			      (void*)&print_server, (void *)&tcs[i]) +	      ) == 0); + +      /*  +       * Wait for thread initialisation +       */ +      { +	int trylock = 0; + +	while (trylock == 0) +	  { +	    trylock = pthread_mutex_trylock(&tcs[i].mutex_started); +	    assert(trylock == 0 || trylock == EBUSY); + +	    if (trylock == 0) +	      { +		assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0); +	      } +	  } +      } +    } + +  dowork (); + +  /* +   * Terminate threads +   */ +  todo = -2;	/* please terminate */ +  dosync(); + +  for (i = 0; i < nthreads; ++i) +    { +      if (0 == tcs[i].stat) +	assert(pthread_join (tcs[i].thread, NULL) == 0); +    } + +  /*  +   * destroy locks +   */ +  assert(pthread_mutex_destroy (&mutex_stdout) == 0); +  assert(pthread_mutex_destroy (&mutex_todo) == 0); + +  /* +   * Cleanup +   */ +  printf ("\n"); + +  /* +   * Show results +   */ +  for (i = 0; i < nthreads; ++i) +    { +      printf ("%2d ", i); +      if (0 == tcs[i].stat) +	printf ("%10ld\n", tcs[i].work); +      else +	printf ("failed %d\n", tcs[i].stat); + +      assert(pthread_mutex_destroy (&tcs[i].mutex_start) == 0); +      assert(pthread_mutex_destroy (&tcs[i].mutex_started) == 0); +      assert(pthread_mutex_destroy (&tcs[i].mutex_end) == 0); +      assert(pthread_mutex_destroy (&tcs[i].mutex_ended) == 0); +    } + +  die (0); + +  return (0);  } diff --git a/tests/mutex2.c b/tests/mutex2.c index 7956f14..b161899 100644 --- a/tests/mutex2.c +++ b/tests/mutex2.c @@ -16,8 +16,14 @@ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  int  main()  { +  assert(mutex == PTHREAD_MUTEX_INITIALIZER); +    assert(pthread_mutex_lock(&mutex) == 0); +  assert(mutex != PTHREAD_MUTEX_INITIALIZER); + +  assert(mutex != NULL); +    assert(pthread_mutex_unlock(&mutex) == 0);    return 0; diff --git a/tests/tsd1.c b/tests/tsd1.c index 93403b1..9448c10 100644 --- a/tests/tsd1.c +++ b/tests/tsd1.c @@ -146,7 +146,7 @@ main()    assert(pthread_key_delete(key) == 0); -  for (i = 0; i < 10; i++) +  for (i = 1; i < 10; i++)      {  	/*  	 * The counter is incremented once when the key is set to @@ -165,5 +165,5 @@ main()    fflush(stderr); -  return (fail) ? 1 : 0; +  return (fail);  } | 
