Conditional Variable pseudocode.
================================

       int pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *mutex);
       int pthread_cond_signal    (pthread_cond_t *cv);
       int pthread_cond_broadcast (pthread_cond_t *cv);

struct pthread_cond_t {

   unsigned int cond_lock;

         internal mutex

   uint64_t total_seq;

     Total number of threads using the conditional variable.

   uint64_t wakeup_seq;

     sequence number for next wakeup.

   uint64_t woken_seq;

     sequence number of last woken thread.

   uint32_t broadcast_seq;

}


struct cv_data {

   pthread_cond_t *cv;

   uint32_t bc_seq

}



cleanup_handler(cv_data)
{
  cv = cv_data->cv;
  lll_lock(cv->lock);

  if (cv_data->bc_seq == cv->broadcast_seq) {
    ++cv->wakeup_seq;
    ++cv->woken_seq;
  }

  /* make sure no signal gets lost.  */
  FUTEX_WAKE(cv->wakeup_seq, ALL);

  lll_unlock(cv->lock);
}


cond_timedwait(cv, mutex, timeout):
{
   lll_lock(cv->lock);
   mutex_unlock(mutex);

   cleanup_push

   ++cv->total_seq;
   val = seq =  cv->wakeup_seq;
   cv_data.bc = cv->broadcast_seq;
   cv_data.cv = cv;

   while (1) {

     lll_unlock(cv->lock);

     enable_async(&cv_data);

     ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);

     restore_async

     lll_lock(cv->lock);

     if (bc != cv->broadcast_seq)
       goto bc_out;

     val = cv->wakeup_seq;

     if (val != seq && cv->woken_seq != val) {
       ret = 0;
       break;
     }

     if (ret == TIMEDOUT) {
       ++cv->wakeup_seq;
       break;
     }
   }

   ++cv->woken_seq;

 bc_out:
   lll_unlock(cv->lock);

   cleanup_pop

   mutex_lock(mutex);

   return ret;
}

cond_signal(cv)
{
   lll_lock(cv->lock);

   if (cv->total_seq > cv->wakeup_seq) {
     ++cv->wakeup_seq;
     FUTEX_WAKE(cv->wakeup_seq, 1);
   }

   lll_unlock(cv->lock);
}

cond_broadcast(cv)
{
   lll_lock(cv->lock);

   if (cv->total_seq > cv->wakeup_seq) {
     cv->wakeup_seq = cv->total_seq;
     cv->woken_seq = cv->total_seq;
     ++cv->broadcast_seq;
     FUTEX_WAKE(cv->wakeup_seq, ALL);
   }

   lll_unlock(cv->lock);
}
