/**
* @file lib/fifo.c
- * @brief Non-thread-safe fifo (FIFO) implementation, based on hash tables.
+ * @brief Non-thread-safe fifo (FIFO) implementation.
*
* @copyright 2005,2006 The FreeRADIUS server project
* @copyright 2005 Alan DeKok <aland@ox.org>
#include <freeradius-devel/libradius.h>
struct fr_fifo_t {
- unsigned int num;
- unsigned int first, last;
- unsigned int max;
- fr_fifo_free_t free_node;
+ unsigned int num; //!< How many elements exist in the fifo.
+ unsigned int first, last; //!< Head and tail indexes for the fifo.
+ unsigned int max; //!< How many elements were created in the fifo.
+ fr_fifo_free_t free_node; //!< Function to call to free nodes when the fifo is freed.
void *data[1];
};
-
-fr_fifo_t *fr_fifo_create(TALLOC_CTX *ctx, int max, fr_fifo_free_t free_node)
-{
- fr_fifo_t *fi;
-
- if ((max < 2) || (max > (1024 * 1024))) return NULL;
-
- fi = talloc_zero_size(ctx, (sizeof(*fi) + (sizeof(fi->data[0])*max)));
- if (!fi) return NULL;
- talloc_set_type(fi, fr_fifo_t);
-
- fi->max = max;
- fi->free_node = free_node;
-
- return fi;
-}
-
-void fr_fifo_free(fr_fifo_t *fi)
+/** Free a fifo and optionally, any data still enqueued
+ *
+ * @param[in] fi to free.
+ * @return 0
+ */
+static int _fifo_free(fr_fifo_t *fi)
{
unsigned int i;
- if (!fi) return;
-
if (fi->free_node) {
for (i = 0 ; i < fi->num; i++) {
unsigned int element;
}
memset(fi, 0, sizeof(*fi));
- talloc_free(fi);
+
+ return 0;
}
+/** Create a fifo queue
+ *
+ * The first element enqueued will be the first to be dequeued.
+ *
+ * @note The created fifo does not provide any thread synchronisation functionality
+ * such as mutexes. If multiple threads are enqueueing and dequeueing data
+ * the callers must synchronise their access.
+ *
+ * @param[in] ctx to allocate fifo array in.
+ * @param[in] max The maximum number of elements allowed.
+ * @param[in] free_node Function to use to free node data if the fifo is freed.
+ * @return
+ * - A new fifo queue.
+ * - NULL on error.
+ */
+fr_fifo_t *fr_fifo_create(TALLOC_CTX *ctx, int max, fr_fifo_free_t free_node)
+{
+ fr_fifo_t *fi;
+
+ if ((max < 2) || (max > (1024 * 1024))) return NULL;
+
+ fi = talloc_zero_size(ctx, (sizeof(*fi) + (sizeof(fi->data[0])*max)));
+ if (!fi) return NULL;
+ talloc_set_type(fi, fr_fifo_t);
+ talloc_set_destructor(fi, _fifo_free);
+
+ fi->max = max;
+ fi->free_node = free_node;
+
+ return fi;
+}
+
+/** Push data onto the fifo
+ *
+ * @param[in] fi FIFO to push data onto.
+ * @param[in] data to push.
+ * @return
+ * - 0 on success.
+ * - -1 on error.
+ */
int fr_fifo_push(fr_fifo_t *fi, void *data)
{
- if (!fi || !data) return 0;
+ if (!fi || !data) return -1;
- if (fi->num >= fi->max) return 0;
+ if (fi->num >= fi->max) return -1;
fi->data[fi->last++] = data;
if (fi->last >= fi->max) fi->last = 0;
fi->num++;
- return 1;
+ return 0;
}
+/** Pop data off of the fifo
+ *
+ * @param[in] fi FIFO to pop data from.
+ * @return
+ * - The data popped.
+ * - NULL if the queue is empty.
+ */
void *fr_fifo_pop(fr_fifo_t *fi)
{
void *data;
return data;
}
+/** Examine the next element that would be popped
+ *
+ * @param[in] fi FIFO to peek at.
+ * @return
+ * - The data at the head of the queue
+ * - NULL if the queue is empty.
+ */
void *fr_fifo_peek(fr_fifo_t *fi)
{
if (!fi || (fi->num == 0)) return NULL;
return fi->data[fi->first];
}
+/** Return the number of elements in the fifo queue
+ *
+ * @param[in] fi FIFO to count elements in.
+ * @return the number of elements
+ */
unsigned int fr_fifo_num_elements(fr_fifo_t *fi)
{
if (!fi) return 0;
for (i = 0; i < SPLIT; i++) {
array[COUNT % MAX] = COUNT;
- if (!fr_fifo_push(fi, &array[COUNT % MAX])) {
+ if (fr_fifo_push(fi, &array[COUNT % MAX]) < 0) {
fprintf(stderr, "%d %d\tfailed pushing %d\n",
j, i, COUNT);
fr_exit(2);
}
}
- fr_fifo_free(fi);
+ talloc_free(fi);
fr_exit(0);
}