/* pthreads implementation, by Craig Vanderborgh, craigv@voxware.com) */

/*---------------------------------------------------------------------------*
 * DESCRIPTION
 * Initialize a condition variable
 *---------------------------------------------------------------------------*/
{
  if (!cond)
    return PTHR_FAILURE;

  cond->defunct = TRUE;  
  if ((cond->waitersMsgQ = msgQCreate(PTHR_MAX_WAITERS, sizeof(Int),
                                     MSG_Q_FIFO)) == NULL)
    return PTHR_FAILURE;
  cond->defunct = FALSE;
  return PTHR_SUCCESS;
}

Int
pthread_cond_destroy(pthread_cond_t * cond)
/*---------------------------------------------------------------------------*
 * DESCRIPTION
 * Destroy a condition variable
 *---------------------------------------------------------------------------*/
{
  Int tid;

  if (!cond)
    return PTHR_FAILURE;

  cond->defunct = TRUE;
  while (msgQNumMsgs(cond->waitersMsgQ) > 0) {
    if (msgQReceive(cond->waitersMsgQ, (char *)&tid, sizeof(Int),
                    WAIT_FOREVER) == ERROR) {
      VBX_print("ERROR: pthread_cond_signal can't read waiter tid\n");
      return PTHR_FAILURE;
    }
    if (taskResume(tid) == ERROR) {
      VBX_print("ERROR: pthread_cond_signal can't restart task %d\n", tid);
      return PTHR_FAILURE;
    }
  }
  
  if (msgQDelete(cond->waitersMsgQ) == ERROR) {
    VBX_print("ERROR: pthread_cond_destroy can't delete msgQ!\n");
    return PTHR_FAILURE;
  }

  return PTHR_SUCCESS;
}

Int
pthread_cond_wait(pthread_cond_t * cond , pthread_mutex_t * mutex)
/*---------------------------------------------------------------------------*
 * DESCRIPTION
 * Wait on a condition variable
 *---------------------------------------------------------------------------*/
{
  Int tid, status;

  if (!cond || !mutex || cond->defunct)
    return PTHR_FAILURE;

  tid = taskIdSelf();  

  if (msgQSend(cond->waitersMsgQ, (char *) &tid, sizeof(Int), 
               WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR) {
    VBX_print("ERROR: pthread_cond_wait can't place taskId on waiters msgQ\n");
    return PTHR_FAILURE;
  }

  if (pthread_mutex_unlock(mutex) != PTHR_SUCCESS) {
    VBX_print("ERROR: pthread_cond_wait can't unlock mutex %x\n", mutex);
    return PTHR_FAILURE;
  }

  if ((status = taskSuspend(tid)) != OK) {
    VBX_print("ERROR: pthread_cond_wait can't suspend task 5d\n", tid);
    return PTHR_FAILURE;
  }

  if (pthread_mutex_lock(mutex) != PTHR_SUCCESS) {
    VBX_print("ERROR: pthread_cond_wait can't reacquire mutex %x\n", mutex);
    return PTHR_FAILURE;
  }

  return PTHR_SUCCESS;
}

Int
pthread_cond_timedwait(pthread_cond_t * cond , pthread_mutex_t * mutex, 
                       const struct timespec * abstime)
/*---------------------------------------------------------------------------*
 * DESCRIPTION
 * Cop-out version of a timed condition variable wait
 *---------------------------------------------------------------------------*/
{
  Int tid, status;

  if (!cond || !mutex || !abstime)
    return PTHR_FAILURE;

  if (pthread_mutex_unlock(mutex) != PTHR_SUCCESS) {
    VBX_print("ERROR: pthread_cond_wait can't unlock mutex %x\n", mutex);
    return PTHR_FAILURE;
  }

  pthread_delay_np(abstime);

  if (pthread_mutex_lock(mutex) != PTHR_SUCCESS) {
    VBX_print("ERROR: pthread_cond_wait can't reacquire mutex %x\n", mutex);
    return PTHR_FAILURE;
  }

  return PTHR_SUCCESS;
}

Int
pthread_cond_signal(pthread_cond_t * cond)
/*---------------------------------------------------------------------------*
 * DESCRIPTION
 * Signal a condition variable
 *---------------------------------------------------------------------------*/
{
  Int tid, status;

  if (!cond || cond->defunct)
    return PTHR_FAILURE;

  if (msgQNumMsgs(cond->waitersMsgQ) > 0) {
    if (msgQReceive(cond->waitersMsgQ, (char *)&tid, sizeof(Int),
                    WAIT_FOREVER) == ERROR) {
      VBX_print("ERROR: pthread_cond_signal can't read waiter tid\n");
      return PTHR_FAILURE;
    }
    if (taskResume(tid) == ERROR) {
      VBX_print("ERROR: pthread_cond_signal can't restart task %d\n", tid);
      return PTHR_FAILURE;
    }
  }

  return PTHR_SUCCESS;
}


