/**
 * Waits on a conditional, handling interruptions and thread state.
 */
IDATA condvar_wait_impl(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano, IDATA interruptable) {
    int r;
    int disable_count;
    hythread_t self;
    
    self = tm_self_tls;

    // check interrupted flag
    if (interruptable && self->interrupted) {
        // clean interrupted flag
        IDATA status = hythread_clear_interrupted_other(self);
        assert(status == TM_ERROR_INTERRUPT);
        return TM_ERROR_INTERRUPT;
    }

    // Store provided cond into current thread cond
    self->current_condition = interruptable ? cond : NULL;

    disable_count = hythread_reset_suspend_disable();

    r = os_cond_timedwait(cond, mutex, ms, nano);

    hythread_set_suspend_disable(disable_count);

    self->current_condition = NULL;
   
    // check interrupted flag
    if (interruptable &&  self->interrupted) {
        // clean interrupted flag
        IDATA status = hythread_clear_interrupted_other(self);
        assert(status == TM_ERROR_INTERRUPT);
        return TM_ERROR_INTERRUPT;
    }

    return r;
}
/**
 * Instructs the current thread to wait until signaled to wake up or timeout.
 * Directly using OS interfaces.
 * This function does not implement interruptability and thread state functionality.
 */
IDATA VMCALL hycond_wait_timed_raw(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) {
    return os_cond_timedwait(cond, mutex, ms, nano);
}
/******************************************************************************
* Function: jpeg_queue_dequeue
* Description: Dequeue a entry from the queue.  It returns the double pointer
*              to the entry to be denqueued from the head of queue,
*              and accepts the number of time in mini-seconds that it conditional  .
*              waits if the queue if empty.
* Input parameters:
*   queue              - The queue object.
*   pp_dequeue_buffer  - The double pointer to dequeued entry.
*   ms                 - The time out in minisecond
* Return values:
*     JPEGERR_SUCCESS
*     JPEGERR_EFAILED
*     JPEGERR_ENULLPTR
*     JPEGERR_ETIMEDOUT
* Notes: none
*****************************************************************************/
int jpeg_queue_dequeue(
    jpeg_queue_t   queue,
    void           **pp_dequeue_entry,
    uint32_t       time_out_ms)
{
    uint32_t   q_index;
    jpeg_q_t   *p_q;
    int        rc;

    // Input parameter validation
    if (!pp_dequeue_entry)
    {
        JPEG_DBG_ERROR("jpeg_queue_dequeue: failed with input parameter check\n");
        return JPEGERR_EBADPARM;
    }
    p_q = (jpeg_q_t *)queue;
    if (!p_q)
    {
        JPEG_DBG_ERROR("jpeg_queue_dequeue: failed with empty queue pointer\n");
        return JPEGERR_ENULLPTR;
    }

    os_mutex_lock(&(p_q->mutex));

    if (p_q->state == QUEUE_STATE_ABORTED)
    {
        os_mutex_unlock(&(p_q->mutex));
        JPEG_DBG_ERROR("jpeg_queue_dequeue: Aborted \n");
        return JPEGERR_EFAILED;
    }

    // Check if queue is empty:
    // queue_cnt is current number of entries in queue.
    while (p_q->queue_cnt <= 0 && QUEUE_STATE_ABORT != p_q->state)
    {
        p_q->state = QUEUE_STATE_TIMEWAIT;
        // fails after conditional waiting time_out_ms in milli-seconds
        rc = os_cond_timedwait(&(p_q->get_cond), &(p_q->mutex), time_out_ms);
        if (JPEG_FAILED(rc))
        {
            JPEG_DBG_ERROR("jpeg_queue_dequeue: failed with empty queue\n");
            if (QUEUE_STATE_ABORT == p_q->state)
            {
                p_q->state = QUEUE_STATE_ABORTED;
                os_cond_signal(&(p_q->abort_cond));
            }
            p_q->state = QUEUE_STATE_IDLE;
            os_mutex_unlock(&(p_q->mutex));
            return rc;
        }
    }

    if (QUEUE_STATE_ABORT == p_q->state)
    {
        p_q->state = QUEUE_STATE_IDLE;
        // signal abort cond
        os_cond_signal(&(p_q->abort_cond));
        os_mutex_unlock(&(p_q->mutex));
        JPEG_DBG_ERROR("jpeg_queue_dequeue: failed with abort\n");
        return JPEGERR_EFAILED;
    }

    // Dequeue an entry from queue
    q_index = p_q->queue_head;

    // Dequeue the entry from the head of queue
    *pp_dequeue_entry = p_q->queue_pool[q_index].p_data;

    // Update the head of queue and entries number
    p_q->queue_head = QUEUE_MOD(p_q->queue_head + 1);
    p_q->queue_cnt  -= 1;
    p_q->state = QUEUE_STATE_IDLE;

    os_mutex_unlock(&(p_q->mutex));
    return JPEGERR_SUCCESS;
}