/* ** Copyright (C) 2004-2006 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** ** Circular buffer API ** */ #include "silk.h" RCSIDENT("$SiLK: circbuf.c 2920 2006-02-06 18:02:36Z mthomas $"); #include "circbuf.h" typedef void (*cleanupHandler)(void *); typedef struct circBuf_struct_t { uint32_t maxsize; /* Maximum number of cells */ uint32_t size; /* Current number of cells in use */ uint32_t cellsize; /* Size of a single cell */ uint32_t head; /* Index of next unused cell */ uint32_t tail; /* Index of oldest unprocessed used cell */ uint8_t *data; /* The cell data */ pthread_mutex_t mutex; /* Mutex */ pthread_cond_t cond; /* Condition variable */ unsigned destroyed : 1; /* Whether we are being destroyed */ unsigned init_head : 1; /* Whether our first head has been asked for */ unsigned writing : 1; unsigned reading : 1; } circBuf_struct_t; /* ** +---+---+---+---+---+---+---+ ** | | u | d | d | d | f | | ** +---+---+---+---+---+---+---+ ** t h ** ** d = data ** f = being filled ** u = data-in-use ** t = tail index ** h = head index ** = unused ** */ circBuf_t circBufCreate(uint32_t item_size, uint32_t size) { circBuf_t buf; if (size < 3) { return NULL; } buf = (circBuf_t)calloc(1, sizeof(circBuf_struct_t)); if (buf == NULL) { return NULL; } buf->data = (uint8_t *)calloc(size, item_size); if (buf->data == NULL) { free(buf); return NULL; } buf->maxsize = size; buf->cellsize = item_size; pthread_mutex_init(&buf->mutex, NULL); pthread_cond_init(&buf->cond, NULL); return buf; } uint8_t *circBufNextHead(circBuf_t buf) { uint8_t *retval; pthread_cleanup_push((cleanupHandler)pthread_mutex_unlock, (void *)(&buf->mutex)); pthread_mutex_lock(&buf->mutex); buf->writing = 1; if (++buf->head == buf->maxsize) { buf->head = 0; } retval = &buf->data[buf->head * buf->cellsize]; while (!buf->destroyed && (buf->size == buf->maxsize - 2)) { pthread_cond_wait(&buf->cond, &buf->mutex); } if (buf->destroyed) { retval = NULL; } else if (!buf->init_head) { buf->init_head = 1; /* Do not increment size the first time */ } else if (buf->size++ == 0) { /* Used to be empty */ pthread_cond_broadcast(&buf->cond); } buf->writing = 0; if (buf->destroyed) { pthread_cond_broadcast(&buf->cond); } pthread_cleanup_pop(1); return retval; } uint8_t *circBufNextTail(circBuf_t buf) { uint8_t *retval; pthread_cleanup_push((cleanupHandler)pthread_mutex_unlock, (void *)(&buf->mutex)); pthread_mutex_lock(&buf->mutex); buf->reading = 1; while (!buf->destroyed && buf->size == 0) { pthread_cond_wait(&buf->cond, &buf->mutex); } if (buf->destroyed) { retval = NULL; } else { if (buf->size-- == buf->maxsize - 2) { /* We were full, we will be no longer after this */ pthread_cond_broadcast(&buf->cond); } if (++buf->tail == buf->maxsize) { buf->tail = 0; } retval = &buf->data[buf->tail * buf->cellsize]; } buf->reading = 0; if (buf->destroyed) { pthread_cond_broadcast(&buf->cond); } pthread_cleanup_pop(1); return retval; } void circBufDestroy(circBuf_t buf) { pthread_cleanup_push((cleanupHandler)pthread_mutex_unlock, (void *)(&buf->mutex)); pthread_mutex_lock(&buf->mutex); buf->destroyed = 1; pthread_cond_broadcast(&buf->cond); while (buf->reading || buf->writing) { pthread_cond_wait(&buf->cond, &buf->mutex); } pthread_cleanup_pop(1); pthread_mutex_destroy(&buf->mutex); pthread_cond_destroy(&buf->cond); free(buf->data); free(buf); }