/* cf_queue_pop * if ms_wait < 0, wait forever * if ms_wait = 0, don't wait at all * if ms_wait > 0, wait that number of ms * */ int cf_queue_pop(cf_queue *q, void *buf, int ms_wait) { if (NULL == q) { cf_error("cf_queue_pop: try passing in a queue"); return(-1); } #ifdef EXTERNAL_LOCKS if (ms_wait != CF_QUEUE_NOWAIT) { // this implementation won't wait cf_error("cf_queue_pop: only nowait supported"); return(-1); } #endif // EXTERNAL_LOCKS QUEUE_LOCK(q); struct timespec tp; if (ms_wait > 0) { #ifdef OSX uint64_t curms = cf_getms(); // using the cl generic functions defined in cf_clock.h. It is going to have slightly less resolution than the pure linux version tp.tv_sec = (curms + ms_wait)/1000; tp.tv_nsec = (ms_wait %1000) * 1000000; #else // linux clock_gettime( CLOCK_REALTIME, &tp); tp.tv_sec += ms_wait / 1000; tp.tv_nsec += (ms_wait % 1000) * 1000000; if (tp.tv_nsec > 1000000000) { tp.tv_nsec -= 1000000000; tp.tv_sec++; } #endif } /* FIXME error checking */ /* Note that we apparently have to use a while() loop. Careful reading * of the pthread_cond_signal() documentation says that AT LEAST ONE * waiting thread will be awakened... */ if (q->threadsafe) { #ifdef EXTERNAL_LOCKS if (CF_Q_EMPTY(q)) { QUEUE_UNLOCK(q); return(CF_QUEUE_EMPTY); } #else while (CF_Q_EMPTY(q)) { if (CF_QUEUE_FOREVER == ms_wait) { pthread_cond_wait(&q->CV, &q->LOCK); } else if (CF_QUEUE_NOWAIT == ms_wait) { pthread_mutex_unlock(&q->LOCK); return(CF_QUEUE_EMPTY); } else { pthread_cond_timedwait(&q->CV, &q->LOCK, &tp); if (CF_Q_EMPTY(q)) { pthread_mutex_unlock(&q->LOCK); return(CF_QUEUE_EMPTY); } } } #endif // EXTERNAL_LOCKS } else if (CF_Q_EMPTY(q)) return(CF_QUEUE_EMPTY); memcpy(buf, CF_Q_ELEM_PTR(q,q->read_offset), q->elementsz); q->read_offset++; // interesting idea - this probably keeps the cache fresher // because the queue is fully empty just make it all zero if (q->read_offset == q->write_offset) { q->read_offset = q->write_offset = 0; } QUEUE_UNLOCK(q); return(0); }
/* cf_queue_pop * if ms_wait < 0, wait forever * if ms_wait = 0, don't wait at all * if ms_wait > 0, wait that number of ms * */ int cf_queue_pop(cf_queue *q, void *buf, int ms_wait) { if (NULL == q) return(-1); /* FIXME error checking */ if (q->threadsafe && (0 != pthread_mutex_lock(&q->LOCK))) return(-1); struct timespec tp; if (ms_wait > 0) { clock_gettime( CLOCK_REALTIME, &tp); tp.tv_sec += ms_wait / 1000; tp.tv_nsec += (ms_wait % 1000) * 1000000; if (tp.tv_nsec > 1000000000) { tp.tv_nsec -= 1000000000; tp.tv_sec++; } } /* FIXME error checking */ /* Note that we apparently have to use a while() loop. Careful reading * of the pthread_cond_signal() documentation says that AT LEAST ONE * waiting thread will be awakened... */ if (q->threadsafe) { while (CF_Q_EMPTY(q)) { if (CF_QUEUE_FOREVER == ms_wait) { pthread_cond_wait(&q->CV, &q->LOCK); } else if (CF_QUEUE_NOWAIT == ms_wait) { pthread_mutex_unlock(&q->LOCK); return(CF_QUEUE_EMPTY); } else { pthread_cond_timedwait(&q->CV, &q->LOCK, &tp); if (CF_Q_EMPTY(q)) { pthread_mutex_unlock(&q->LOCK); return(CF_QUEUE_EMPTY); } } } } else if (CF_Q_EMPTY(q)) return(CF_QUEUE_EMPTY); memcpy(buf, CF_Q_ELEM_PTR(q,q->read_offset), q->elementsz); q->read_offset++; // interesting idea - this probably keeps the cache fresher // because the queue is fully empty just make it all zero if (q->read_offset == q->write_offset) { q->read_offset = q->write_offset = 0; } /* FIXME blow a gasket */ if (q->threadsafe && (0 != pthread_mutex_unlock(&q->LOCK))) { // cf_info(CF_QUEUE, "queue pop failed"); return(-1); } return(0); }