⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 condvar.c

📁 SIP 1.5.0源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
       * Check again.
       */
      if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
        {
          /*
           * 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.
           */
          *cond = NULL;
        }
      else
        {
          /*
           * The cv has been initialised while we were waiting
           * so assume it's in use.
           */
          result = EBUSY;
        }

      LeaveCriticalSection(&ptw32_cond_test_init_lock);
    }

  return (result);
}

/*
 * Arguments for cond_wait_cleanup, since we can only pass a
 * single void * to it.
 */
typedef struct {
  pthread_mutex_t * mutexPtr;
  pthread_cond_t cv;
  int * resultPtr;
} ptw32_cond_wait_cleanup_args_t;

static void
ptw32_cond_wait_cleanup(void * args)
{
  ptw32_cond_wait_cleanup_args_t * cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args;
  pthread_mutex_t * mutexPtr = cleanup_args->mutexPtr;
  pthread_cond_t cv = cleanup_args->cv;
  int * resultPtr = cleanup_args->resultPtr;
  int lastWaiter = FALSE;

  /*
   * Whether we got here legitimately or because of an error we
   * indicate that we are no longer waiting. The alternative
   * will result in never signaling the broadcasting thread.
   */
  if (pthread_mutex_lock (&(cv->waitersLock)) == 0)
    {
      /*
       * The waiter is responsible for decrementing
       * its count, protected by an internal mutex.
       */

      cv->waiters--;

      lastWaiter = cv->wasBroadcast && (cv->waiters == 0);

      if (lastWaiter)
        {
          cv->wasBroadcast = FALSE;
        }

      (void) pthread_mutex_unlock (&(cv->waitersLock));
    }

  /*
   * If we are the last waiter on this broadcast
   * let the thread doing the broadcast proceed
   */
  if (lastWaiter && !SetEvent (cv->waitersDone))
    {
      *resultPtr = EINVAL;
    }

  /*
   * We must always regain the external mutex, even when
   * errors occur, because that's the guarantee that we give
   * to our callers.
   *
   * Note that the broadcasting thread may already own the lock.
   * The standard actually requires that the signaling thread hold
   * the lock at the time that it signals if the developer wants
   * predictable scheduling behaviour. It's up to the developer.
   * In that case all waiting threads will block here until
   * the broadcasting thread releases the lock, having been
   * notified by the last waiting thread (SetEvent call above).
   */
  (void) pthread_mutex_lock (mutexPtr);
}

static int
ptw32_cond_timedwait (pthread_cond_t * cond, 
                      pthread_mutex_t * mutex,
                      const struct timespec *abstime)
{
  int result = 0;
  pthread_cond_t cv;
  ptw32_cond_wait_cleanup_args_t cleanup_args;

  if (cond == NULL || *cond == NULL)
    {
      return EINVAL;
    }

  /*
   * We do a quick check to see if we need to do more work
   * to initialise a static condition variable. We check
   * again inside the guarded section of ptw32_cond_check_need_init()
   * to avoid race conditions.
   */
  if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
    {
      result = ptw32_cond_check_need_init(cond);
    }

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

  cv = *cond;

  /*
   * It's not OK to increment cond->waiters while the caller locked 'mutex',
   * there may be other threads just waking up (with 'mutex' unlocked)
   * and cv->... data is not protected.
   */
  if (pthread_mutex_lock(&(cv->waitersLock)) != 0)
    {
      return EINVAL;
    }

  cv->waiters++;

  if (pthread_mutex_unlock(&(cv->waitersLock)) != 0)
    {
      return EINVAL;
    }

  /*
   * We keep the lock held just long enough to increment the count of
   * waiters by one (above).
   * Note that we can't keep it held across the
   * call to sem_wait since that will deadlock other calls
   * to pthread_cond_signal
   */
  cleanup_args.mutexPtr = mutex;
  cleanup_args.cv = cv;
  cleanup_args.resultPtr = &result;

  pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);

  if ((result = pthread_mutex_unlock (mutex)) == 0)
    {
      /*
       * Wait to be awakened by
       *              pthread_cond_signal, or
       *              pthread_cond_broadcast, or
       *              a timeout
       *
       * Note: 
       *      ptw32_sem_timedwait is a cancelation point,
       *      hence providing the
       *      mechanism for making pthread_cond_wait a cancelation
       *      point. We use the cleanup mechanism to ensure we
       *      re-lock the mutex and decrement the waiters count
       *      if we are canceled.
       */
      if (ptw32_sem_timedwait (&(cv->sema), abstime) == -1)
	{
	  result = errno;
	}
    }

  pthread_cleanup_pop (1);  /* Always cleanup */

  /*
   * "result" can be modified by the cleanup handler.
   * Specifically, if we are the last waiting thread and failed
   * to notify the broadcast thread to proceed.
   */
  return (result);

}                               /* ptw32_cond_timedwait */


int
pthread_cond_wait (pthread_cond_t * cond,
		   pthread_mutex_t * mutex)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function waits on a condition variable until
      *      awakened by a signal or broadcast.
      *
      *      Caller MUST be holding the mutex lock; the
      *      lock is released and the caller is blocked waiting
      *      on 'cond'. When 'cond' is signaled, the mutex
      *      is re-acquired before returning to the caller.
      *
      * PARAMETERS
      *      cond
      *              pointer to an instance of pthread_cond_t
      *
      *      mutex
      *              pointer to an instance of pthread_mutex_t
      *
      *
      * DESCRIPTION
      *      This function waits on a condition variable until
      *      awakened by a signal or broadcast.
      *
      *      NOTES:
      *      1)      The function must be called with 'mutex' LOCKED
      *               by the calling thread, or undefined behaviour
      *              will result.
      *
      *      2)      This routine atomically releases 'mutex' and causes
      *              the calling thread to block on the condition variable.
      *              The blocked thread may be awakened by 
      *                      pthread_cond_signal or 
      *                      pthread_cond_broadcast.
      *
      * Upon successful completion, the 'mutex' has been locked and 
      * is owned by the calling thread.
      *
      *
      * RESULTS
      *              0               caught condition; mutex released,
      *              EINVAL          'cond' or 'mutex' is invalid,
      *              EINVAL          different mutexes for concurrent waits,
      *              EINVAL          mutex is not held by the calling thread,
      *
      * ------------------------------------------------------
      */
{
  /* The NULL abstime arg means INFINITE waiting. */
  return(ptw32_cond_timedwait(cond, mutex, NULL));
}                               /* pthread_cond_wait */


int
pthread_cond_timedwait (pthread_cond_t * cond, 
                        pthread_mutex_t * mutex,
                        const struct timespec *abstime)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function waits on a condition variable either until
      *      awakened by a signal or broadcast; or until the time
      *      specified by abstime passes.
      *
      * PARAMETERS
      *      cond
      *              pointer to an instance of pthread_cond_t
      *
      *      mutex
      *              pointer to an instance of pthread_mutex_t
      *
      *      abstime
      *              pointer to an instance of (const struct timespec)
      *
      *
      * DESCRIPTION
      *      This function waits on a condition variable either until
      *      awakened by a signal or broadcast; or until the time
      *      specified by abstime passes.
      *
      *      NOTES:
      *      1)      The function must be called with 'mutex' LOCKED
      *               by the calling thread, or undefined behaviour
      *              will result.
      *
      *      2)      This routine atomically releases 'mutex' and causes
      *              the calling thread to block on the condition variable.
      *              The blocked thread may be awakened by 
      *                      pthread_cond_signal or 
      *                      pthread_cond_broadcast.
      *
      *
      * RESULTS
      *              0               caught condition; mutex released,
      *              EINVAL          'cond', 'mutex', or abstime is invalid,
      *              EINVAL          different mutexes for concurrent waits,
      *              EINVAL          mutex is not held by the calling thread,
      *              ETIMEDOUT       abstime ellapsed before cond was signaled.
      *
      * ------------------------------------------------------
      */
{
  int result = 0;

  if (abstime == NULL)
    {
      result = EINVAL;
    }
  else
    {
      result = ptw32_cond_timedwait(cond, mutex, abstime);
    }

  return(result);
}                               /* pthread_cond_timedwait */


int
pthread_cond_signal (pthread_cond_t * cond)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function signals a condition variable, waking
      *      one waiting thread.
      *      If SCHED_FIFO or SCHED_RR policy threads are waiting
      *      the highest priority waiter is awakened; otherwise,
      *      an unspecified waiter is awakened.
      *
      * PARAMETERS
      *      cond
      *              pointer to an instance of pthread_cond_t
      *
      *
      * DESCRIPTION
      *      This function signals a condition variable, waking
      *      one waiting thread.
      *      If SCHED_FIFO or SCHED_RR policy threads are waiting
      *      the highest priority waiter is awakened; otherwise,
      *      an unspecified waiter is awakened.
      *
      *      NOTES:
      *      1)      Use when any waiter can respond and only one need
      *              respond (all waiters being equal).
      *
      *      2)      This function MUST be called under the protection 
      *              of the SAME mutex that is used with the condition
      *              variable being signaled; OTHERWISE, the condition
      *              variable may be signaled between the test of the
      *              associated condition and the blocking
      *              pthread_cond_signal.
      *              This can cause an infinite wait.
      *
      * RESULTS
      *              0               successfully signaled condition,
      *              EINVAL          'cond' is invalid,
      *
      * ------------------------------------------------------
      */
{
  int result = 0;
  pthread_cond_t cv;

  if (cond == NULL || *cond == NULL)
    {
      return EINVAL;
    }

  cv = *cond;

  /*
   * No-op if the CV is static and hasn't been initialised yet.
   * Assuming that race conditions are harmless.
   */
  if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
    {
      return 0;
    }

  /*
   * If there aren't any waiters, then this is a no-op.
   * Assuming that race conditions are harmless.
   */
  if (cv->waiters > 0)
    {
      result = sem_post (&(cv->sema));
    }

  return (result);

}                               /* pthread_cond_signal */

int
pthread_cond_broadcast (pthread_cond_t * cond)
     /*
      * ------------------------------------------------------
      * DOCPUBLIC
      *      This function broadcasts the condition variable,
      *      waking all current waiters.
      *
      * PARAMETERS
      *      cond
      *              pointer to an instance of pthread_cond_t
      *
      *
      * DESCRIPTION
      *      This function signals a condition variable, waking
      *      all waiting threads.
      *
      *      NOTES:
      *      1)      This function MUST be called under the protection
      *              of the SAME mutex that is used with the condition
      *              variable being signaled; OTHERWISE, the condition
      *              variable may be signaled between the test of the
      *              associated condition and the blocking pthread_cond_wait.
      *              This can cause an infinite wait.
      *
      *      2)      Use when more than one waiter may respond to
      *              predicate change or if any waiting thread may
      *              not be able to respond
      *
      * RESULTS
      *              0               successfully signalled condition to all
      *                              waiting threads,
      *              EINVAL          'cond' is invalid
      *              ENOSPC          a required resource has been exhausted,
      *
      * ------------------------------------------------------
      */
{
  int result = 0;
  int wereWaiters = FALSE;
  pthread_cond_t cv;

  if (cond == NULL || *cond == NULL)
    {
      return EINVAL;
    }

  cv = *cond;

  /*
   * No-op if the CV is static and hasn't been initialised yet.
   * Assuming that any race condition is harmless.
   */
  if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
    {
      return 0;
    }

  if (pthread_mutex_lock(&(cv->waitersLock)) == EINVAL)
    {
      return EINVAL;
    }

  cv->wasBroadcast = TRUE;
  wereWaiters = (cv->waiters > 0);

  if (wereWaiters)
    {
      /*
       * Wake up all waiters
       */

#ifdef NEED_SEM

      result = (ptw32_increase_semaphore( &cv->sema, cv->waiters )
		? 0
		: EINVAL);

#else /* NEED_SEM */

      result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL )
		? 0
		: EINVAL);

#endif /* NEED_SEM */

    }

  (void) pthread_mutex_unlock(&(cv->waitersLock));

  if (wereWaiters && result == 0)
    {
      /*
       * Wait for all the awakened threads to acquire their part of
       * the counting semaphore
       */
      if (WaitForSingleObject (cv->waitersDone, INFINITE)
          == WAIT_OBJECT_0)
        {
          result = 0;
        }
      else
        {
          result = EINVAL;
        }

    }

  return (result);

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -