Пример #1
0
/*
 * Pop a clean pthread_t struct off the reuse stack.
 */
pthread_t
ptw32_threadReusePop (void)
{
  pthread_t t = {NULL, 0};
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

  if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseTop)
    {
      ptw32_thread_t * tp;

      tp = ptw32_threadReuseTop;

      ptw32_threadReuseTop = tp->prevReuse;

      if (PTW32_THREAD_REUSE_EMPTY == ptw32_threadReuseTop)
        {
          ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY;
        }

      tp->prevReuse = PTW32_THREAD_REUSE_EMPTY;

      t = tp->ptHandle;
    }

  ptw32_mcs_lock_release(&node);

  return t;
}
Пример #2
0
static void PTW32_CDECL
ptw32_once_on_init_cancel (void * arg)
{
  /* when the initting thread is cancelled we have to release the lock */
  ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)arg;
  ptw32_mcs_lock_release(node);
}
Пример #3
0
int
pthread_getname_np(pthread_t thr, char *name, int len)
{
  ptw32_mcs_local_node_t threadLock;
  ptw32_thread_t * tp;
  char * s, * d;
  int result;

  /*
   * Validate the thread id. This method works for pthreads-win32 because
   * pthread_kill and pthread_t are designed to accommodate it, but the
   * method is not portable.
   */
  result = pthread_kill (thr, 0);
  if (0 != result)
    {
      return result;
    }

  tp = (ptw32_thread_t *) thr.p;

  ptw32_mcs_lock_acquire (&tp->threadLock, &threadLock);

  for (s = tp->name, d = name; *s && d < &name[len - 1]; *d++ = *s++)
    {}

  *d = '\0';
  ptw32_mcs_lock_release (&threadLock);

  return result;
}
Пример #4
0
int
pthread_kill (pthread_t thread, int sig)
{
  int result = 0;
  ptw32_thread_t * tp;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

  tp = (ptw32_thread_t *) thread.p;

  if (NULL == tp
      || thread.x != tp->ptHandle.x
      || NULL == tp->threadH)
    {
      result = ESRCH;
    }

  ptw32_mcs_lock_release(&node);

  if (0 == result && 0 != sig)
    {
      result = EINVAL;
    }

  return result;

}				
Пример #5
0
int
pthread_kill (pthread_t thread, int sig)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function requests that a signal be delivered to the
      *      specified thread. If sig is zero, error checking is
      *      performed but no signal is actually sent such that this
      *      function can be used to check for a valid thread ID.
      *
      * PARAMETERS
      *      thread  reference to an instances of pthread_t
      *      sig     signal. Currently only a value of 0 is supported.
      *
      *
      * DESCRIPTION
      *      This function requests that a signal be delivered to the
      *      specified thread. If sig is zero, error checking is
      *      performed but no signal is actually sent such that this
      *      function can be used to check for a valid thread ID.
      *
      * RESULTS
      *              ESRCH           the thread is not a valid thread ID,
      *              EINVAL          the value of the signal is invalid
      *                              or unsupported.
      *              0               the signal was successfully sent.
      *
      * ------------------------------------------------------
      */
{
  int result = 0;
  ptw32_thread_t * tp;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

  tp = (ptw32_thread_t *) thread.p;

  if (NULL == tp
      || thread.x != tp->ptHandle.x
      || NULL == tp->threadH)
    {
      result = ESRCH;
    }

  ptw32_mcs_lock_release(&node);

  if (0 == result && 0 != sig)
    {
      /*
       * Currently does not support any signals.
       */
      result = EINVAL;
    }

  return result;

}				/* pthread_kill */
BOOL
pthread_win32_thread_detach_np ()
{
  if (ptw32_processInitialized)
    {
      /*
       * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle
       * unnecessarily.
       */
      ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);

      if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle.
	{
          ptw32_mcs_local_node_t stateLock;
	  ptw32_callUserDestroyRoutines (sp->ptHandle);

	  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
	  sp->state = PThreadStateLast;
	  /*
	   * If the thread is joinable at this point then it MUST be joined
	   * or detached explicitly by the application.
	   */
	  ptw32_mcs_lock_release (&stateLock);

          /*
           * Robust Mutexes
           */
          while (sp->robustMxList != NULL)
            {
              pthread_mutex_t mx = sp->robustMxList->mx;
              ptw32_robust_mutex_remove(&mx, sp);
              (void) PTW32_INTERLOCKED_EXCHANGE_LONG(
                       (PTW32_INTERLOCKED_LONGPTR)&mx->robustNode->stateInconsistent,
                       (PTW32_INTERLOCKED_LONG)-1);
              /*
               * If there are no waiters then the next thread to block will
               * sleep, wake up immediately and then go back to sleep.
               * See pthread_mutex_lock.c.
               */
              SetEvent(mx->event);
            }


	  if (sp->detachState == PTHREAD_CREATE_DETACHED)
	    {
	      ptw32_threadDestroy (sp->ptHandle);

	      if (ptw32_selfThreadKey)
	        {
	    	  TlsSetValue (ptw32_selfThreadKey->key, NULL);
	        }
	    }
	}
    }

  return TRUE;
}
Пример #7
0
int
sem_trywait (sem_t * sem)
/*
 * ------------------------------------------------------
 * DOCPUBLIC
 *      This function tries to wait on a semaphore.
 *
 * PARAMETERS
 *      sem
 *              pointer to an instance of sem_t
 *
 * DESCRIPTION
 *      This function tries to wait on a semaphore. If the
 *      semaphore value is greater than zero, it decreases
 *      its value by one. If the semaphore value is zero, then
 *      this function returns immediately with the error EAGAIN
 *
 * RESULTS
 *              0               successfully decreased semaphore,
 *              -1              failed, error in errno
 * ERRNO
 *              EAGAIN          the semaphore was already locked,
 *              EINVAL          'sem' is not a valid semaphore,
 *              ENOTSUP         sem_trywait is not supported,
 *              EINTR           the function was interrupted by a signal,
 *              EDEADLK         a deadlock condition was detected.
 *
 * ------------------------------------------------------
 */
{
  int result = 0;
  sem_t s = *sem;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&s->lock, &node);

  if (s->value > 0)
    {
      s->value--;
    }
  else
    {
      result = EAGAIN;
    }

  ptw32_mcs_lock_release(&node);

  if (result != 0)
    {
      PTW32_SET_ERRNO(result);
      return -1;
    }

  return 0;

}				/* sem_trywait */
Пример #8
0
int
ptw32_setthreadpriority (
    ptw32_handle_t thread, int policy, int priority)
{
  int prio;
  ptw32_mcs_local_node_t threadLock;
  int result = 0;
  ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;

  prio = priority;

  /* Validate priority level. */
  if (prio < sched_get_priority_min (policy) ||
      prio > sched_get_priority_max (policy))
    {
      return EINVAL;
    }

#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
/* WinCE */
#else
/* Everything else */

  if (THREAD_PRIORITY_IDLE < prio && THREAD_PRIORITY_LOWEST > prio)
    {
      prio = THREAD_PRIORITY_LOWEST;
    }
  else if (THREAD_PRIORITY_TIME_CRITICAL > prio
	   && THREAD_PRIORITY_HIGHEST < prio)
    {
      prio = THREAD_PRIORITY_HIGHEST;
    }

#endif

  ptw32_mcs_lock_acquire (&tp->threadLock, &threadLock);

  /* If this fails, the current priority is unchanged. */
  if (0 == SetThreadPriority (tp->threadH, prio))
    {
      result = EINVAL;
    }
  else
    {
      /*
       * Must record the thread's sched_priority as given,
       * not as finally adjusted.
       */
      tp->sched_priority = priority;
    }

  ptw32_mcs_lock_release (&threadLock);

  return result;
}
int
pthread_barrier_wait (pthread_barrier_t * barrier)
{
  int result;
  pthread_barrier_t b;

  ptw32_mcs_local_node_t node;

  if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)
    {
      return EINVAL;
    }

  ptw32_mcs_lock_acquire(&(*barrier)->lock, &node);

  b = *barrier;
  if (--b->nCurrentBarrierHeight == 0)
    {
      ptw32_mcs_node_transfer(&b->proxynode, &node);

      result = (b->nInitialBarrierHeight > 1
                ? sem_post_multiple (&(b->semBarrierBreeched),
				     b->nInitialBarrierHeight - 1) : 0);
    }
  else
    {
      ptw32_mcs_lock_release(&node);
      result = ptw32_semwait (&(b->semBarrierBreeched));
    }

  if ((PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_INCREMENT_LONG((PTW32_INTERLOCKED_LONGPTR)&b->nCurrentBarrierHeight)
		  == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight)
    {
      ptw32_mcs_lock_release(&b->proxynode);
      if (0 == result)
        {
          result = PTHREAD_BARRIER_SERIAL_THREAD;
        }
    }

  return (result);
}
int
pthread_setcanceltype (int type, int *oldtype)
{
  ptw32_mcs_local_node_t stateLock;
  int result = 0;
  pthread_t self = pthread_self ();
  ptw32_thread_t * sp = (ptw32_thread_t *) self.p;

  if (sp == NULL
      || (type != PTHREAD_CANCEL_DEFERRED
	  && type != PTHREAD_CANCEL_ASYNCHRONOUS))
    {
      return EINVAL;
    }

  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);

  if (oldtype != NULL)
    {
      *oldtype = sp->cancelType;
    }

  sp->cancelType = type;

  if (sp->cancelState == PTHREAD_CANCEL_ENABLE
      && type == PTHREAD_CANCEL_ASYNCHRONOUS
      && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0)
    {
      sp->state = PThreadStateCanceling;
      sp->cancelState = PTHREAD_CANCEL_DISABLE;
      ResetEvent (sp->cancelEvent);
      ptw32_mcs_lock_release (&stateLock);
      ptw32_throw (PTW32_EPS_CANCEL);

      
    }

  ptw32_mcs_lock_release (&stateLock);

  return (result);

}				
int
ptw32_setthreadpriority (pthread_t thread, int policy, int priority)
{
  int prio;
  ptw32_mcs_local_node_t threadLock;
  int result = 0;
  ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;

  prio = priority;

  
  if (prio < sched_get_priority_min (policy) ||
      prio > sched_get_priority_max (policy))
    {
      return EINVAL;
    }

#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
#else

  if (THREAD_PRIORITY_IDLE < prio && THREAD_PRIORITY_LOWEST > prio)
    {
      prio = THREAD_PRIORITY_LOWEST;
    }
  else if (THREAD_PRIORITY_TIME_CRITICAL > prio
	   && THREAD_PRIORITY_HIGHEST < prio)
    {
      prio = THREAD_PRIORITY_HIGHEST;
    }

#endif

  ptw32_mcs_lock_acquire (&tp->threadLock, &threadLock);

  
  if (0 == SetThreadPriority (tp->threadH, prio))
    {
      result = EINVAL;
    }
  else
    {
      tp->sched_priority = priority;
    }

  ptw32_mcs_lock_release (&threadLock);

  return result;
}
void *
pthread_timechange_handler_np (void *arg)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      Broadcasts all CVs to force re-evaluation and
      *      new timeouts if required.
      *
      * PARAMETERS
      *      NONE
      *
      *
      * DESCRIPTION
      *      Broadcasts all CVs to force re-evaluation and
      *      new timeouts if required.
      *
      *      This routine may be passed directly to pthread_create()
      *      as a new thread in order to run asynchronously.
      *
      *
      * RESULTS
      *              0               successfully broadcast all CVs
      *              EAGAIN          Not all CVs were broadcast
      *
      * ------------------------------------------------------
      */
{
  int result = 0;
  pthread_cond_t cv;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node);

  cv = ptw32_cond_list_head;

  while (cv != NULL && 0 == result)
    {
      result = pthread_cond_broadcast (&cv);
      cv = cv->next;
    }

  ptw32_mcs_lock_release(&node);

  return (void *) (size_t) (result != 0 ? EAGAIN : 0);
}
INLINE int
ptw32_mutex_check_need_init (pthread_mutex_t * mutex)
{
  register int result = 0;
  register pthread_mutex_t mtx;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_mutex_test_init_lock, &node);

  /*
   * 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.
   */
  mtx = *mutex;

  if (mtx == PTHREAD_MUTEX_INITIALIZER)
    {
      result = pthread_mutex_init (mutex, NULL);
    }
  else if (mtx == PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
    {
      result = pthread_mutex_init (mutex, &ptw32_recursive_mutexattr);
    }
  else if (mtx == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
    {
      result = pthread_mutex_init (mutex, &ptw32_errorcheck_mutexattr);
    }
  else if (mtx == NULL)
    {
      /*
       * The mutex has been destroyed while we were waiting to
       * initialise it, so the operation that caused the
       * auto-initialisation should fail.
       */
      result = EINVAL;
    }

  ptw32_mcs_lock_release(&node);

  return (result);
}
INLINE int
ptw32_cond_check_need_init (pthread_cond_t * cond)
{
  int result = 0;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node);

  if (*cond == PTHREAD_COND_INITIALIZER)
    {
      result = pthread_cond_init (cond, NULL);
    }
  else if (*cond == NULL)
    {
      result = EINVAL;
    }

  ptw32_mcs_lock_release(&node);

  return result;
}
Пример #15
0
int
pthread_once (pthread_once_t * once_control, void (PTW32_CDECL *init_routine) (void))
{
  if (once_control == NULL || init_routine == NULL)
    {
      return EINVAL;
    }
  
  if ((PTW32_INTERLOCKED_LONG)PTW32_FALSE ==
      (PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_EXCHANGE_ADD_LONG((PTW32_INTERLOCKED_LONGPTR)&once_control->done,
                                                                  (PTW32_INTERLOCKED_LONG)0)) /* MBR fence */
    {
      ptw32_mcs_local_node_t node;

      ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node);

      if (!once_control->done)
	{

#if defined(_MSC_VER) && _MSC_VER < 1400
#pragma inline_depth(0)
#endif

	  pthread_cleanup_push(ptw32_mcs_lock_release, &node);
	  (*init_routine)();
	  pthread_cleanup_pop(0);

#if defined(_MSC_VER) && _MSC_VER < 1400
#pragma inline_depth()
#endif

	  once_control->done = PTW32_TRUE;
	}

	ptw32_mcs_lock_release(&node);
    }

  return 0;

}				/* pthread_once */
Пример #16
0
static void PTW32_CDECL
ptw32_sem_timedwait_cleanup (void * args)
{
  ptw32_mcs_local_node_t node;
  sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args;
  sem_t s = a->sem;

  ptw32_mcs_lock_acquire(&s->lock, &node);
  /*
   * We either timed out or were cancelled.
   * If someone has posted between then and now we try to take the semaphore.
   * Otherwise the semaphore count may be wrong after we
   * return. In the case of a cancellation, it is as if we
   * were cancelled just before we return (after taking the semaphore)
   * which is ok.
   */
  if (WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0)
    {
      /* We got the semaphore on the second attempt */
      *(a->resultPtr) = 0;
    }
  else
    {
      /* Indicate we're no longer waiting */
      s->value++;
#if defined(NEED_SEM)
      if (s->value > 0)
        {
          s->leftToUnblock = 0;
        }
#else
      /*
       * Don't release the W32 sema, it doesn't need adjustment
       * because it doesn't record the number of waiters.
       */
#endif
    }
  ptw32_mcs_lock_release(&node);
}
Пример #17
0
/*
 * Push a clean pthread_t struct onto the reuse stack.
 * Must be re-initialised when reused.
 * All object elements (mutexes, events etc) must have been either
 * destroyed before this, or never initialised.
 */
void
ptw32_threadReusePush (pthread_t thread)
{
  ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
  pthread_t t;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

  t = tp->ptHandle;
  memset(tp, 0, sizeof(ptw32_thread_t));

  /* Must restore the original POSIX handle that we just wiped. */
  tp->ptHandle = t;

  /* Bump the reuse counter now */
#if defined(PTW32_THREAD_ID_REUSE_INCREMENT)
  tp->ptHandle.x += PTW32_THREAD_ID_REUSE_INCREMENT;
#else
  tp->ptHandle.x++;
#endif

  tp->state = PThreadStateReuse;

  tp->prevReuse = PTW32_THREAD_REUSE_EMPTY;

  if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseBottom)
    {
      ptw32_threadReuseBottom->prevReuse = tp;
    }
  else
    {
      ptw32_threadReuseTop = tp;
    }

  ptw32_threadReuseBottom = tp;

  ptw32_mcs_lock_release(&node);
}
Пример #18
0
int
pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
{
  if (once_control == NULL || init_routine == NULL)
    {
      return EINVAL;
    }
  
  if (InterlockedExchangeAdd((LPLONG)&once_control->init, 0L)) /* MBR fence */
    {
      ptw32_mcs_local_node_t node;

      ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node);

      if (once_control->init)
	{

#ifdef _MSC_VER
#pragma inline_depth(0)
#endif

	  pthread_cleanup_push(ptw32_once_on_init_cancel, (void *)&node);
	  (*init_routine)();
	  pthread_cleanup_pop(0);

#ifdef _MSC_VER
#pragma inline_depth()
#endif

	  once_control->init = 0;
	}

	ptw32_mcs_lock_release(&node);
    }

  return 0;

}				/* pthread_once */
Пример #19
0
int
ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock)
{
    int result = 0;
    ptw32_mcs_local_node_t node;

    /*
     * The following guarded test is specifically for statically
     * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER).
     */
    ptw32_mcs_lock_acquire(&ptw32_rwlock_test_init_lock, &node);

    /*
     * We got here possibly under race
     * conditions. Check again inside the critical section
     * and only initialise if the rwlock is valid (not been destroyed).
     * If a static rwlock has been destroyed, the application can
     * re-initialise it only by calling pthread_rwlock_init()
     * explicitly.
     */
    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
    {
        result = pthread_rwlock_init (rwlock, NULL);
    }
    else if (*rwlock == NULL)
    {
        /*
         * The rwlock has been destroyed while we were waiting to
         * initialise it, so the operation that caused the
         * auto-initialisation should fail.
         */
        result = EINVAL;
    }

    ptw32_mcs_lock_release(&node);

    return result;
}
Пример #20
0
int
ptw32_cond_check_need_init (pthread_cond_t * cond)
{
  int result = 0;
  ptw32_mcs_local_node_t node;

  /*
   * The following guarded test is specifically for statically
   * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER).
   */
  ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node);

  /*
   * 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 == PTHREAD_COND_INITIALIZER)
    {
      result = pthread_cond_init (cond, NULL);
    }
  else if (*cond == NULL)
    {
      /*
       * The cv has been destroyed while we were waiting to
       * initialise it, so the operation that caused the
       * auto-initialisation should fail.
       */
      result = EINVAL;
    }

  ptw32_mcs_lock_release(&node);

  return result;
}
Пример #21
0
int
pthread_cond_destroy (pthread_cond_t * cond)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function destroys a condition variable
      *
      *
      * PARAMETERS
      *      cond
      *              pointer to an instance of pthread_cond_t
      *
      *
      * DESCRIPTION
      *      This function destroys a condition variable.
      *
      *      NOTES:
      *              1)      A condition variable can be destroyed
      *                      immediately after all the threads that
      *                      are blocked on it are awakened. e.g.
      *
      *                      struct list {
      *                        pthread_mutex_t lm;
      *                        ...
      *                      }
      *
      *                      struct elt {
      *                        key k;
      *                        int busy;
      *                        pthread_cond_t notbusy;
      *                        ...
      *                      }
      *
      *                      
      *                      struct elt *
      *                      list_find(struct list *lp, key k)
      *                      {
      *                        struct elt *ep;
      *
      *                        pthread_mutex_lock(&lp->lm);
      *                        while ((ep = find_elt(l,k) != NULL) && ep->busy)
      *                          pthread_cond_wait(&ep->notbusy, &lp->lm);
      *                        if (ep != NULL)
      *                          ep->busy = 1;
      *                        pthread_mutex_unlock(&lp->lm);
      *                        return(ep);
      *                      }
      *
      *                      delete_elt(struct list *lp, struct elt *ep)
      *                      {
      *                        pthread_mutex_lock(&lp->lm);
      *                        assert(ep->busy);
      *                        ... remove ep from list ...
      *                        ep->busy = 0;
      *                    (A) pthread_cond_broadcast(&ep->notbusy);
      *                        pthread_mutex_unlock(&lp->lm);
      *                    (B) pthread_cond_destroy(&rp->notbusy);
      *                        free(ep);
      *                      }
      *
      *                      In this example, the condition variable
      *                      and its list element may be freed (line B)
      *                      immediately after all threads waiting for
      *                      it are awakened (line A), since the mutex
      *                      and the code ensure that no other thread
      *                      can touch the element to be deleted.
      *
      * RESULTS
      *              0               successfully released condition variable,
      *              EINVAL          'cond' is invalid,
      *              EBUSY           'cond' is in use,
      *
      * ------------------------------------------------------
      */
{
  pthread_cond_t cv;
  int result = 0, result1 = 0, result2 = 0;

  /*
   * Assuming any race condition here is harmless.
   */
  if (cond == NULL || *cond == NULL)
    {
      return EINVAL;
    }

  if (*cond != PTHREAD_COND_INITIALIZER)
    {
      ptw32_mcs_local_node_t node;
      ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node);

      cv = *cond;

      /*
       * Close the gate; this will synchronize this thread with
       * all already signaled waiters to let them retract their
       * waiter status - SEE NOTE 1 ABOVE!!!
       */
      if (ptw32_semwait (&(cv->semBlockLock)) != 0) /* Non-cancelable */
	{
	  result = PTW32_GET_ERRNO();
	}
      else
        {
          /*
           * !TRY! lock mtxUnblockLock; try will detect busy condition
           * and will not cause a deadlock with respect to concurrent
           * signal/broadcast.
           */
          if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0)
	    {
	      (void) sem_post (&(cv->semBlockLock));
	    }
	}
	
      if (result != 0)
        {
          ptw32_mcs_lock_release(&node);
          return result;
        }

      /*
       * Check whether cv is still busy (still has waiters)
       */
      if (cv->nWaitersBlocked > cv->nWaitersGone)
	{
	  if (sem_post (&(cv->semBlockLock)) != 0)
	    {
	      result = PTW32_GET_ERRNO();
	    }
	  result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock));
	  result2 = EBUSY;
	}
      else
	{
	  /*
	   * Now it is safe to destroy
	   */
	  *cond = NULL;

	  if (sem_destroy (&(cv->semBlockLock)) != 0)
	    {
	      result = PTW32_GET_ERRNO();
	    }
	  if (sem_destroy (&(cv->semBlockQueue)) != 0)
	    {
	      result1 = PTW32_GET_ERRNO();
	    }
	  if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0)
	    {
	      result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock));
	    }

	  /* Unlink the CV from the list */

	  if (ptw32_cond_list_head == cv)
	    {
	      ptw32_cond_list_head = cv->next;
	    }
	  else
	    {
	      cv->prev->next = cv->next;
	    }

	  if (ptw32_cond_list_tail == cv)
	    {
	      ptw32_cond_list_tail = cv->prev;
	    }
	  else
	    {
	      cv->next->prev = cv->prev;
	    }

	  (void) free (cv);
	}

      ptw32_mcs_lock_release(&node);
    }
  else
    {
      ptw32_mcs_local_node_t node;
      /*
       * See notes in ptw32_cond_check_need_init() above also.
       */
      ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node);

      /*
       * Check again.
       */
      if (*cond == PTHREAD_COND_INITIALIZER)
	{
	  /*
	   * This is all we need to do to destroy a statically
	   * initialised cond that has not yet been used (initialised).
	   * If we get to here, another thread waiting to initialise
	   * this cond will get an EINVAL. That's OK.
	   */
	  *cond = NULL;
	}
      else
	{
	  /*
	   * The cv has been initialised while we were waiting
	   * so assume it's in use.
	   */
	  result = EBUSY;
	}

      ptw32_mcs_lock_release(&node);
    }

  return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
}
Пример #22
0
int
pthread_timedjoin_np (pthread_t thread, void **value_ptr, const struct timespec *abstime)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function waits for 'thread' to terminate and
      *      returns the thread's exit value if 'value_ptr' is not
      *      NULL or until 'abstime' passes and returns an
      *      error. If 'abstime' is NULL then the function waits
      *      forever, i.e. reverts to pthread_join behaviour.
      *      This function detaches the thread on successful
      *      completion.
      *
      * PARAMETERS
      *      thread
      *              an instance of pthread_t
      *
      *      value_ptr
      *              pointer to an instance of pointer to void
      *
      *      abstime
      *              pointer to an instance of struct timespec
      *              representing an absolute time value
      *
      *
      * DESCRIPTION
      *      This function waits for 'thread' to terminate and
      *      returns the thread's exit value if 'value_ptr' is not
      *      NULL or until 'abstime' passes and returns an
      *      error. If 'abstime' is NULL then the function waits
      *      forever, i.e. reverts to pthread_join behaviour.
      *      This function detaches the thread on successful
      *      completion.
      *      NOTE:   Detached threads cannot be joined or canceled.
      *              In this implementation 'abstime' will be
      *              resolved to the nearest millisecond.
      *
      * RESULTS
      *              0               'thread' has completed
      *              ETIMEDOUT       abstime passed
      *              EINVAL          thread is not a joinable thread,
      *              ESRCH           no thread could be found with ID 'thread',
      *              ENOENT          thread couldn't find it's own valid handle,
      *              EDEADLK         attempt to join thread with self
      *
      * ------------------------------------------------------
      */
{
  int result;
  pthread_t self;
  DWORD milliseconds;
  ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
  ptw32_mcs_local_node_t node;

  if (abstime == NULL)
    {
      milliseconds = INFINITE;
    }
  else
    {
      /*
       * Calculate timeout as milliseconds from current system time.
       */
      milliseconds = ptw32_relmillisecs (abstime);
    }

  ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

  if (NULL == tp
      || thread.x != tp->ptHandle.x)
    {
      result = ESRCH;
    }
  else if (PTHREAD_CREATE_DETACHED == tp->detachState)
    {
      result = EINVAL;
    }
  else
    {
      result = 0;
    }

  ptw32_mcs_lock_release(&node);

  if (result == 0)
    {
      /*
       * The target thread is joinable and can't be reused before we join it.
       */
      self = pthread_self();

      if (NULL == self.p)
        {
          result = ENOENT;
        }
      else if (pthread_equal (self, thread))
        {
          result = EDEADLK;
        }
      else
        {
          /*
           * Pthread_join is a cancellation point.
           * If we are canceled then our target thread must not be
           * detached (destroyed). This is guaranteed because
           * pthreadCancelableTimedWait will not return if we
           * are canceled.
           */
          result = pthreadCancelableTimedWait (tp->threadH, milliseconds);

          if (0 == result)
            {
              if (value_ptr != NULL)
                {
                  *value_ptr = tp->exitStatus;
                }

              /*
               * The result of making multiple simultaneous calls to
               * pthread_join() or pthread_timedjoin_np() or pthread_detach()
               * specifying the same target is undefined.
               */
              result = pthread_detach (thread);
            }
          else if (ETIMEDOUT != result)
            {
              result = ESRCH;
            }
        }
    }

  return (result);

}
Пример #23
0
int
pthread_barrier_wait (pthread_barrier_t * barrier)
{
  int result;
  pthread_barrier_t b;

  ptw32_mcs_local_node_t node;

  if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)
    {
      return EINVAL;
    }

  ptw32_mcs_lock_acquire(&(*barrier)->lock, &node);

  b = *barrier;
  if (--b->nCurrentBarrierHeight == 0)
    {
      /*
       * We are the last thread to arrive at the barrier before it releases us.
       * Move our MCS local node to the global scope barrier handle so that the
       * last thread out (not necessarily us) can release the lock.
       */
      ptw32_mcs_node_transfer(&b->proxynode, &node);

      /*
       * Any threads that have not quite entered sem_wait below when the
       * multiple_post has completed will nevertheless continue through
       * the semaphore (barrier).
       */
      result = (b->nInitialBarrierHeight > 1
                ? sem_post_multiple (&(b->semBarrierBreeched),
				     b->nInitialBarrierHeight - 1) : 0);
    }
  else
    {
      ptw32_mcs_lock_release(&node);
      /*
       * Use the non-cancelable version of sem_wait().
       *
       * It is possible that all nInitialBarrierHeight-1 threads are
       * at this point when the last thread enters the barrier, resets
       * nCurrentBarrierHeight = nInitialBarrierHeight and leaves.
       * If pthread_barrier_destroy is called at that moment then the
       * barrier will be destroyed along with the semas.
       */
      result = ptw32_semwait (&(b->semBarrierBreeched));
    }

  if ((PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_INCREMENT_LONG((PTW32_INTERLOCKED_LONGPTR)&b->nCurrentBarrierHeight)
		  == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight)
    {
      /*
       * We are the last thread to cross this barrier
       */
      ptw32_mcs_lock_release(&b->proxynode);
      if (0 == result)
        {
          result = PTHREAD_BARRIER_SERIAL_THREAD;
        }
    }

  return (result);
}
Пример #24
0
static INLINE int
ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
     /*
      * -------------------------------------------------------------------
      * This provides an extra hook into the pthread_cancel
      * mechanism that will allow you to wait on a Windows handle and make it a
      * cancellation point. This function blocks until the given WIN32 handle is
      * signaled or pthread_cancel has been called. It is implemented using
      * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32
      * event used to implement pthread_cancel.
      * 
      * Given this hook it would be possible to implement more of the cancellation
      * points.
      * -------------------------------------------------------------------
      */
{
  int result;
  pthread_t self;
  ptw32_thread_t * sp;
  HANDLE handles[2];
  DWORD nHandles = 1;
  DWORD status;

  handles[0] = waitHandle;

  self = pthread_self();
  sp = (ptw32_thread_t *) to_internal(self).p;

  if (sp != NULL)
    {
      /*
       * Get cancelEvent handle
       */
      if (sp->cancelState == PTHREAD_CANCEL_ENABLE)
	{

	  if ((handles[1] = sp->cancelEvent) != NULL)
	    {
	      nHandles++;
	    }
	}
    }
  else
    {
      handles[1] = NULL;
    }

  status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout);

  switch (status - WAIT_OBJECT_0)
    {
    case 0:
      /*
       * Got the handle.
       * In the event that both handles are signalled, the smallest index
       * value (us) is returned. As it has been arranged, this ensures that
       * we don't drop a signal that we should act on (i.e. semaphore,
       * mutex, or condition variable etc).
       */
      result = 0;
      break;

    case 1:
      /*
       * Got cancel request.
       * In the event that both handles are signaled, the cancel will
       * be ignored (see case 0 comment).
       */
      ResetEvent (handles[1]);

      if (sp != NULL)
	{
          ptw32_mcs_local_node_t stateLock;
	  /*
	   * Should handle POSIX and implicit POSIX threads..
	   * Make sure we haven't been async-canceled in the meantime.
	   */
	  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
	  if (sp->state < PThreadStateCanceling)
	    {
	      sp->state = PThreadStateCanceling;
	      sp->cancelState = PTHREAD_CANCEL_DISABLE;
	      ptw32_mcs_lock_release (&stateLock);
	      ptw32_throw (PTW32_EPS_CANCEL);

	      /* Never reached */
	    }
	  ptw32_mcs_lock_release (&stateLock);
	}

      /* Should never get to here. */
      result = EINVAL;
      break;

    default:
      if (status == WAIT_TIMEOUT)
	{
	  result = ETIMEDOUT;
	}
      else
	{
	  result = EINVAL;
	}
      break;
    }

  return (result);

}				/* CancelableWait */
Пример #25
0
int
pthread_cancel (pthread_t thread)
{
    int result;
    int cancel_self;
    pthread_t self;
    ptw32_thread_t * tp;
    ptw32_mcs_local_node_t stateLock;

    result = pthread_kill (thread, 0);

    if (0 != result)
    {
        return result;
    }

    if ((self = pthread_self ()).p == NULL)
    {
        return ENOMEM;
    };

    cancel_self = pthread_equal (thread, self);

    tp = (ptw32_thread_t *) thread.p;

    ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock);

    if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
            && tp->cancelState == PTHREAD_CANCEL_ENABLE
            && tp->state < PThreadStateCanceling)
    {
        if (cancel_self)
        {
            tp->state = PThreadStateCanceling;
            tp->cancelState = PTHREAD_CANCEL_DISABLE;

            ptw32_mcs_lock_release (&stateLock);
            ptw32_throw (PTW32_EPS_CANCEL);


        }
        else
        {
            HANDLE threadH = tp->threadH;

            SuspendThread (threadH);

            if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT)
            {
                tp->state = PThreadStateCanceling;
                tp->cancelState = PTHREAD_CANCEL_DISABLE;
                ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0);
                ptw32_mcs_lock_release (&stateLock);
                ResumeThread (threadH);
            }
        }
    }
    else
    {
        if (tp->state < PThreadStateCancelPending)
        {
            tp->state = PThreadStateCancelPending;
            if (!SetEvent (tp->cancelEvent))
            {
                result = ESRCH;
            }
        }
        else if (tp->state >= PThreadStateCanceling)
        {
            result = ESRCH;
        }

        ptw32_mcs_lock_release (&stateLock);
    }

    return (result);
}
Пример #26
0
int
pthread_barrier_destroy (pthread_barrier_t * barrier)
{
  int result = 0;
  pthread_barrier_t b;
  ptw32_mcs_local_node_t node;

  if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)
    {
      return EINVAL;
    }

  if (0 != ptw32_mcs_lock_try_acquire(&(*barrier)->lock, &node))
    {
      return EBUSY;
    }

  b = *barrier;

  if (b->nCurrentBarrierHeight < b->nInitialBarrierHeight)
    {
      result = EBUSY;
    }
  else
	{
      if (0 == (result = sem_destroy (&(b->semBarrierBreeched))))
        {
          *barrier = (pthread_barrier_t) PTW32_OBJECT_INVALID;
          /*
           * Release the lock before freeing b.
           *
           * FIXME: There may be successors which, when we release the lock,
           * will be linked into b->lock, which will be corrupted at some
           * point with undefined results for the application. To fix this
           * will require changing pthread_barrier_t from a pointer to
           * pthread_barrier_t_ to an instance. This is a change to the ABI
           * and will require a major version number increment.
           */
          ptw32_mcs_lock_release(&node);
	  (void) free (b);
	  return 0;
	}
      else
        {
          /*
           * This should not ever be reached.
           * Restore the barrier to working condition before returning.
           */
          (void) sem_init (&(b->semBarrierBreeched), b->pshared, 0);
        }

      if (result != 0)
        {
          /*
           * The barrier still exists and is valid
           * in the event of any error above.
           */
          result = EBUSY;
        }
    }

  ptw32_mcs_lock_release(&node);
  return (result);
}
int
pthread_setcancelstate (int state, int *oldstate)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function atomically sets the calling thread's
      *      cancelability state to 'state' and returns the previous
      *      cancelability state at the location referenced by
      *      'oldstate'
      *
      * PARAMETERS
      *      state,
      *      oldstate
      *              PTHREAD_CANCEL_ENABLE
      *                      cancellation is enabled,
      *
      *              PTHREAD_CANCEL_DISABLE
      *                      cancellation is disabled
      *
      *
      * DESCRIPTION
      *      This function atomically sets the calling thread's
      *      cancelability state to 'state' and returns the previous
      *      cancelability state at the location referenced by
      *      'oldstate'.
      *
      *      NOTES:
      *      1)      Use to disable cancellation around 'atomic' code that
      *              includes cancellation points
      *
      * COMPATIBILITY ADDITIONS
      *      If 'oldstate' is NULL then the previous state is not returned
      *      but the function still succeeds. (Solaris)
      *
      * RESULTS
      *              0               successfully set cancelability type,
      *              EINVAL          'state' is invalid
      *
      * ------------------------------------------------------
      */
{
  ptw32_mcs_local_node_t stateLock;
  int result = 0;
  pthread_t self = pthread_self ();
  ptw32_thread_t * sp = (ptw32_thread_t *) self.p;

  if (sp == NULL
      || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE))
    {
      return EINVAL;
    }

  /*
   * Lock for async-cancel safety.
   */
  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);

  if (oldstate != NULL)
    {
      *oldstate = sp->cancelState;
    }

  sp->cancelState = state;

  /*
   * Check if there is a pending asynchronous cancel
   */
  if (state == PTHREAD_CANCEL_ENABLE
      && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
      && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0)
    {
      sp->state = PThreadStateCanceling;
      sp->cancelState = PTHREAD_CANCEL_DISABLE;
      ResetEvent (sp->cancelEvent);
      ptw32_mcs_lock_release (&stateLock);
      ptw32_throw (PTW32_EPS_CANCEL);

      /* Never reached */
    }

  ptw32_mcs_lock_release (&stateLock);

  return (result);

}				/* pthread_setcancelstate */
int
pthread_detach (pthread_t thread)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function detaches the given thread.
      *
      * PARAMETERS
      *      thread
      *              an instance of a pthread_t
      *
      *
      * DESCRIPTION
      *      This function detaches the given thread. You may use it to
      *      detach the main thread or to detach a joinable thread.
      *      NOTE:   detached threads cannot be joined;
      *              storage is freed immediately on termination.
      *
      * RESULTS
      *              0               successfully detached the thread,
      *              EINVAL          thread is not a joinable thread,
      *              ENOSPC          a required resource has been exhausted,
      *              ESRCH           no thread could be found for 'thread',
      *
      * ------------------------------------------------------
      */
{
  int result;
  BOOL destroyIt = PTW32_FALSE;
  ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
  ptw32_mcs_local_node_t node;

  ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

  if (NULL == tp
      || thread.x != tp->ptHandle.x)
    {
      result = ESRCH;
    }
  else if (PTHREAD_CREATE_DETACHED == tp->detachState)
    {
      result = EINVAL;
    }
  else
    {
      ptw32_mcs_local_node_t stateLock;
      /*
       * Joinable ptw32_thread_t structs are not scavenged until
       * a join or detach is done. The thread may have exited already,
       * but all of the state and locks etc are still there.
       */
      result = 0;

      ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock);
      if (tp->state != PThreadStateLast)
        {
          tp->detachState = PTHREAD_CREATE_DETACHED;
        }
      else if (tp->detachState != PTHREAD_CREATE_DETACHED)
        {
          /*
           * Thread is joinable and has exited or is exiting.
           */
          destroyIt = PTW32_TRUE;
        }
      ptw32_mcs_lock_release (&stateLock);
    }

  ptw32_mcs_lock_release(&node);

  if (result == 0)
    {
      /* Thread is joinable */

      if (destroyIt)
	{
	  /* The thread has exited or is exiting but has not been joined or
	   * detached. Need to wait in case it's still exiting.
	   */
	  (void) WaitForSingleObject(tp->threadH, INFINITE);
	  ptw32_threadDestroy (thread);
	}
    }

  return (result);

}				/* pthread_detach */
Пример #29
0
int
pthread_setspecific (pthread_key_t key, const void *value)
/*
 * ------------------------------------------------------
 * DOCPUBLIC
 *      This function sets the value of the thread specific
 *      key in the calling thread.
 *
 * PARAMETERS
 *      key
 *              an instance of pthread_key_t
 *      value
 *              the value to set key to
 *
 *
 * DESCRIPTION
 *      This function sets the value of the thread specific
 *      key in the calling thread.
 *
 * RESULTS
 *              0               successfully set value
 *              EAGAIN          could not set value
 *              ENOENT          SERIOUS!!
 *
 * ------------------------------------------------------
 */
{
    pthread_t self;
    int result = 0;

    if (key != ptw32_selfThreadKey)
    {
        /*
         * Using pthread_self will implicitly create
         * an instance of pthread_t for the current
         * thread if one wasn't explicitly created
         */
        self = pthread_self ();
        if (self.p == NULL)
        {
            return ENOENT;
        }
    }
    else
    {
        /*
         * Resolve catch-22 of registering thread with selfThread
         * key
         */
        ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);

        if (sp == NULL)
        {
            if (value == NULL)
            {
                return ENOENT;
            }
            self = *((pthread_t *) value);
        }
        else
        {
            self = sp->ptHandle;
        }
    }

    result = 0;

    if (key != NULL)
    {
        if (self.p != NULL && key->destructor != NULL && value != NULL)
        {
            ptw32_mcs_local_node_t keyLock;
            ptw32_mcs_local_node_t threadLock;
            ptw32_thread_t * sp = (ptw32_thread_t *) self.p;
            /*
             * Only require associations if we have to
             * call user destroy routine.
             * Don't need to locate an existing association
             * when setting data to NULL for WIN32 since the
             * data is stored with the operating system; not
             * on the association; setting assoc to NULL short
             * circuits the search.
             */
            ThreadKeyAssoc *assoc;

            ptw32_mcs_lock_acquire(&(key->keyLock), &keyLock);
            ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock);

            assoc = (ThreadKeyAssoc *) sp->keys;
            /*
             * Locate existing association
             */
            while (assoc != NULL)
            {
                if (assoc->key == key)
                {
                    /*
                     * Association already exists
                     */
                    break;
                }
                assoc = assoc->nextKey;
            }

            /*
             * create an association if not found
             */
            if (assoc == NULL)
            {
                result = ptw32_tkAssocCreate (sp, key);
            }

            ptw32_mcs_lock_release(&threadLock);
            ptw32_mcs_lock_release(&keyLock);
        }

        if (result == 0)
        {
            if (!TlsSetValue (key->key, (LPVOID) value))
            {
                result = EAGAIN;
            }
        }
    }

    return (result);
}				/* pthread_setspecific */
Пример #30
0
int
sem_timedwait (sem_t * sem, const struct timespec *abstime)
/*
 * ------------------------------------------------------
 * DOCPUBLIC
 *      This function waits on a semaphore possibly until
 *      'abstime' time.
 *
 * PARAMETERS
 *      sem
 *              pointer to an instance of sem_t
 *
 *      abstime
 *              pointer to an instance of struct timespec
 *
 * DESCRIPTION
 *      This function waits on a semaphore. If the
 *      semaphore value is greater than zero, it decreases
 *      its value by one. If the semaphore value is zero, then
 *      the calling thread (or process) is blocked until it can
 *      successfully decrease the value or until interrupted by
 *      a signal.
 *
 *      If 'abstime' is a NULL pointer then this function will
 *      block until it can successfully decrease the value or
 *      until interrupted by a signal.
 *
 * RESULTS
 *              0               successfully decreased semaphore,
 *              -1              failed, error in errno
 * ERRNO
 *              EINVAL          'sem' is not a valid semaphore,
 *              ENOSYS          semaphores are not supported,
 *              EINTR           the function was interrupted by a signal,
 *              EDEADLK         a deadlock condition was detected.
 *              ETIMEDOUT       abstime elapsed before success.
 *
 * ------------------------------------------------------
 */
{
  ptw32_mcs_local_node_t node;
  DWORD milliseconds;
  int v;
  int result = 0;
  sem_t s = *sem;

  pthread_testcancel();

  if (abstime == NULL)
    {
      milliseconds = INFINITE;
    }
  else
    {
      /*
       * Calculate timeout as milliseconds from current system time.
       */
      milliseconds = ptw32_relmillisecs (abstime);
    }

  ptw32_mcs_lock_acquire(&s->lock, &node);
  v = --s->value;
  ptw32_mcs_lock_release(&node);

  if (v < 0)
    {
#if defined(NEED_SEM)
      int timedout;
#endif
      sem_timedwait_cleanup_args_t cleanup_args;

      cleanup_args.sem = s;
      cleanup_args.resultPtr = &result;

#if defined(PTW32_CONFIG_MSVC7)
#pragma inline_depth(0)
#endif
      /* Must wait */
      pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args);
#if defined(NEED_SEM)
      timedout =
#endif
          result = pthreadCancelableTimedWait (s->sem, milliseconds);
      pthread_cleanup_pop(result);
#if defined(PTW32_CONFIG_MSVC7)
#pragma inline_depth()
#endif

#if defined(NEED_SEM)

      if (!timedout)
        {
          ptw32_mcs_lock_acquire(&s->lock, &node);
          if (s->leftToUnblock > 0)
            {
              --s->leftToUnblock;
              SetEvent(s->sem);
            }
          ptw32_mcs_lock_release(&node);
        }

#endif /* NEED_SEM */

    }

  if (result != 0)
    {

      PTW32_SET_ERRNO(result);
      return -1;

    }

  return 0;

}				/* sem_timedwait */