From: Arran Cudbard-Bell Date: Sun, 4 Jun 2017 19:45:09 +0000 (-0400) Subject: s/cbuff/fring/ X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4fc3b37fbe1bb1306dda4f34842b79aa0b356ed3;p=thirdparty%2Ffreeradius-server.git s/cbuff/fring/ --- diff --git a/src/include/debug.h b/src/include/debug.h index 373538d36c6..e9dd33c7f50 100644 --- a/src/include/debug.h +++ b/src/include/debug.h @@ -23,7 +23,7 @@ * * @copyright 2015-2017 Arran Cudbard-Bell */ -#include +#include typedef enum { DEBUGGER_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check. @@ -55,9 +55,9 @@ typedef struct fr_bt_marker fr_bt_marker_t; void fr_debug_state_store(void); char const *fr_debug_state_to_msg(fr_debug_state_t state); void fr_debug_break(bool always); -void backtrace_print(fr_cbuff_t *cbuff, void *obj); +void backtrace_print(fr_fring_t *fring, void *obj); int fr_backtrace_do(fr_bt_marker_t *marker); -fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj); +fr_bt_marker_t *fr_backtrace_attach(fr_fring_t **fring, TALLOC_CTX *obj); void fr_panic_on_free(TALLOC_CTX *ctx); int fr_set_dumpable_init(void); diff --git a/src/include/cbuff.h b/src/include/fring.h similarity index 73% rename from src/include/cbuff.h rename to src/include/fring.h index 2e1c17b7edc..31807ff5713 100644 --- a/src/include/cbuff.h +++ b/src/include/fring.h @@ -18,17 +18,18 @@ /* * $Id$ * - * @file include/cbuff.h - * @brief Simple circular buffer for debugging purposes. + * @file include/fring_buffer.h + * @brief Simple ring buffer with fixed element sizes. * * @copyright 2015-2017 Arran Cudbard-Bell */ #include #include -typedef struct fr_cbuff fr_cbuff_t; +typedef struct fr_fring_buffer fr_fring_t; -fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock); -void fr_cbuff_insert(fr_cbuff_t *cbuff, void *obj); -void *fr_cbuff_next(fr_cbuff_t *cbuff); +fr_fring_t *fr_fring_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock); +int fr_fring_overwrite(fr_fring_t *fring, void *obj); +int fr_fring_insert(fr_fring_t *fring, void *obj); +void *fr_fring_next(fr_fring_t *fring); #endif /* _FR_CBUFF_H */ diff --git a/src/lib/util/all.mk b/src/lib/util/all.mk index bc38993bbde..298e0e6827c 100644 --- a/src/lib/util/all.mk +++ b/src/lib/util/all.mk @@ -6,13 +6,13 @@ TARGET := libfreeradius-util.a SOURCES := base64.c \ - cbuff.c \ cursor.c \ debug.c \ dict.c \ event.c \ fifo.c \ filters.c \ + fring.c \ getaddrinfo.c \ hash.c \ heap.c \ diff --git a/src/lib/util/cbuff.c b/src/lib/util/cbuff.c deleted file mode 100644 index d0860447152..00000000000 --- a/src/lib/util/cbuff.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file lib/util/cbuff.c - * @brief Implementation of a ring buffer - * - * @copyright 2013 The FreeRADIUS server project - * @copyright 2013 Arran Cudbard-Bell - */ -RCSID("$Id$") - -#include -#include - -/** Standard thread safe circular buffer - * - */ -struct fr_cbuff { - void const *end; //!< End of allocated memory - - uint32_t size; - uint32_t in; //!< Write index - uint32_t out; //!< Read index - - void **data; //!< Ring buffer data - - bool lock; //!< Perform thread synchronisation - - pthread_mutex_t mutex; //!< Thread synchronisation mutex -}; - -/** Destroy mutex associated with circular buffer - * - * @param[in] cbuff being freed. - * @return 0 - */ -static int _cbuff_free(fr_cbuff_t *cbuff) -{ - void *next; - - if (cbuff->lock) pthread_mutex_destroy(&cbuff->mutex); - - /* - * Free any data left in the buffer - */ - while ((next = fr_cbuff_next(cbuff))) talloc_free(next); - - return 0; -} - -/** Initialise a new circular buffer - * - * @param[in] ctx to allocate the buffer in. - * @param[in] size of buffer to allocate. - * @param[in] lock If true, insert and next operations will lock the buffer. - * @return - * - New cbuff. - * - NULL on error. - */ -fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock) -{ - fr_cbuff_t *cbuff; - - uint32_t pow; - - /* - * Find the nearest power of 2 (rounding up) - */ - for (pow = 0x00000001; - pow < size; - pow <<= 1); - size = pow; - size--; - - cbuff = talloc_zero(ctx, fr_cbuff_t); - if (!cbuff) return NULL; - talloc_set_destructor(cbuff, _cbuff_free); - - cbuff->data = talloc_zero_array(cbuff, void *, size); - if (!cbuff->data) { - talloc_free(cbuff); - return NULL; - } - cbuff->size = size; - - if (lock) { - cbuff->lock = true; - pthread_mutex_init(&cbuff->mutex, NULL); - } - - return cbuff; -} - -/** Insert a new item into the circular buffer - * - * cbuff will steal obj and insert it into it's own context. - * - * @param[in] cbuff to insert item into - * @param[in] in item to insert (must have been allocated with talloc). - */ -void fr_cbuff_insert(fr_cbuff_t *cbuff, void *in) -{ - if (cbuff->lock) pthread_mutex_lock(&cbuff->mutex); - - if (cbuff->data[cbuff->in]) talloc_free(cbuff->data[cbuff->in]); - - cbuff->data[cbuff->in] = in; - cbuff->in = (cbuff->in + 1) & cbuff->size; - - /* overwrite - out is advanced ahead of in */ - if (cbuff->in == cbuff->out) cbuff->out = (cbuff->out + 1) & cbuff->size; - - if (cbuff->lock) pthread_mutex_unlock(&cbuff->mutex); -} - -/** Remove an item from the buffer - * - * @param[in] cbuff to drain data from. - * @return - * - NULL if no dataents in the buffer. - * - An dataent from the buffer reparented to ctx. - */ -void *fr_cbuff_next(fr_cbuff_t *cbuff) -{ - void *out = NULL; - - if (cbuff->lock) pthread_mutex_lock(&cbuff->mutex); - - /* Buffer is empty */ - if (cbuff->out == cbuff->in) goto done; - - out = cbuff->data[cbuff->out]; - cbuff->data[cbuff->out] = NULL; - cbuff->out = (cbuff->out + 1) & cbuff->size; - -done: - if (cbuff->lock) pthread_mutex_unlock(&cbuff->mutex); - - return out; -} diff --git a/src/lib/util/debug.c b/src/lib/util/debug.c index 9d7cfbfd5ee..ff02c29d801 100644 --- a/src/lib/util/debug.c +++ b/src/lib/util/debug.c @@ -77,7 +77,7 @@ typedef struct fr_bt_info { struct fr_bt_marker { void *obj; //!< Pointer to the parent object, this is our needle //!< when we iterate over the contents of the circular buffer. - fr_cbuff_t *cbuff; //!< Where we temporarily store the backtraces + fr_fring_t *fring; //!< Where we temporarily store the backtraces }; #endif @@ -311,15 +311,15 @@ void fr_debug_break(bool always) #ifdef HAVE_EXECINFO /** Print backtrace entry for a given object * - * @param cbuff to search in. + * @param fring to search in. * @param obj pointer to original object */ -void backtrace_print(fr_cbuff_t *cbuff, void *obj) +void backtrace_print(fr_fring_t *fring, void *obj) { fr_bt_info_t *p; bool found = false; - while ((p = fr_cbuff_next(cbuff))) { + while ((p = fr_fring_next(fring))) { if ((p->obj == obj) || !obj) { found = true; @@ -341,7 +341,7 @@ int fr_backtrace_do(fr_bt_marker_t *marker) { fr_bt_info_t *bt; - if (!fr_cond_assert(marker->obj) || !fr_cond_assert(marker->cbuff)) return -1; + if (!fr_cond_assert(marker->obj) || !fr_cond_assert(marker->fring)) return -1; bt = talloc_zero(NULL, fr_bt_info_t); if (!bt) return -1; @@ -349,7 +349,7 @@ int fr_backtrace_do(fr_bt_marker_t *marker) bt->obj = marker->obj; bt->count = backtrace(bt->frames, MAX_BT_FRAMES); - fr_cbuff_insert(marker->cbuff, bt); + fr_fring_overwrite(marker->fring, bt); return 0; } @@ -360,8 +360,8 @@ int fr_backtrace_do(fr_bt_marker_t *marker) * * Code augmentation should look something like: @verbatim - // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it - static fr_cbuff_t *my_obj_bt; + // Create a static fringer pointer, the first call to backtrace_attach will initialise it + static fr_fring_t *my_obj_bt; my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) { my_obj_t *this; @@ -383,17 +383,17 @@ int fr_backtrace_do(fr_bt_marker_t *marker) * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument * values, but should at least show the code path taken. * - * @param cbuff this should be a pointer to a static *fr_cbuff. + * @param fring this should be a pointer to a static *fr_fring_buffer. * @param obj we want to generate a backtrace for. */ -fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj) +fr_bt_marker_t *fr_backtrace_attach(fr_fring_t **fring, TALLOC_CTX *obj) { fr_bt_marker_t *marker; - if (*cbuff == NULL) { + if (*fring == NULL) { pthread_mutex_lock(&fr_debug_init); /* Check again now we hold the mutex - eww*/ - if (*cbuff == NULL) *cbuff = fr_cbuff_alloc(NULL, MAX_BT_CBUFF, true); + if (*fring == NULL) *fring = fr_fring_alloc(NULL, MAX_BT_CBUFF, true); pthread_mutex_unlock(&fr_debug_init); } @@ -403,7 +403,7 @@ fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj) } marker->obj = (void *) obj; - marker->cbuff = *cbuff; + marker->fring = *fring; fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj); /* @@ -415,11 +415,11 @@ fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj) return marker; } #else -void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj) +void backtrace_print(UNUSED fr_fring_t *fring, UNUSED void *obj) { fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n"); } -fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj) +fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_fring_t **fring, UNUSED TALLOC_CTX *obj) { fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n"); abort(); diff --git a/src/lib/util/fring.c b/src/lib/util/fring.c new file mode 100644 index 00000000000..1cb2313c76d --- /dev/null +++ b/src/lib/util/fring.c @@ -0,0 +1,193 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file lib/util/fring.c + * @brief Implementation of a circular buffer with fixed element size. + * + * This offers similar functionality to ring_buffer.c, but uses a fixed + * element size, and expects all elements to be talloced. + * + * @copyright 2013 The FreeRADIUS server project + * @copyright 2013 Arran Cudbard-Bell + */ +RCSID("$Id$") + +#include +#include + +/** Standard thread safe circular buffer + * + */ +struct fr_fring_buffer { + void const *end; //!< End of allocated memory + + uint32_t size; + uint32_t in; //!< Write index + uint32_t out; //!< Read index + + void **data; //!< Ring buffer data + + bool lock; //!< Perform thread synchronisation + + pthread_mutex_t mutex; //!< Thread synchronisation mutex +}; + +/** Destroy mutex associated with ring buffer + * + * @param[in] fring being freed. + * @return 0 + */ +static int _fring_free(fr_fring_t *fring) +{ + void *next; + + if (fring->lock) pthread_mutex_destroy(&fring->mutex); + + /* + * Free any data left in the buffer + */ + while ((next = fr_fring_next(fring))) talloc_free(next); + + return 0; +} + +/** Initialise a ring buffer with fixed element size + * + * @param[in] ctx to allocate the buffer in. + * @param[in] size of buffer to allocate. + * @param[in] lock If true, insert and next operations will lock the buffer. + * @return + * - New fring. + * - NULL on error. + */ +fr_fring_t *fr_fring_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock) +{ + fr_fring_t *fring; + + uint32_t pow; + + /* + * Find the nearest power of 2 (rounding up) + */ + for (pow = 0x00000001; + pow < size; + pow <<= 1); + size = pow; + size--; + + fring = talloc_zero(ctx, fr_fring_t); + if (!fring) return NULL; + talloc_set_destructor(fring, _fring_free); + + fring->data = talloc_zero_array(fring, void *, size); + if (!fring->data) { + talloc_free(fring); + return NULL; + } + fring->size = size; + + if (lock) { + fring->lock = true; + pthread_mutex_init(&fring->mutex, NULL); + } + + return fring; +} + +/** Insert a new item into the circular buffer, freeing the tail if we hit it + * + * @param[in] fring to insert item into + * @param[in] in item to insert (must have been allocated with talloc). + * @return + * - 0 if we inserted the item without freeing existing items. + * - 1 if we inserted the item, but needed to free an existing item. + */ +int fr_fring_overwrite(fr_fring_t *fring, void *in) +{ + bool freed = false; + if (fring->lock) pthread_mutex_lock(&fring->mutex); + + if (fring->data[fring->in]) { + freed = true; + talloc_free(fring->data[fring->in]); + } + + fring->data[fring->in] = in; + fring->in = (fring->in + 1) & fring->size; + + /* overwrite - out is advanced ahead of in */ + if (fring->in == fring->out) fring->out = (fring->out + 1) & fring->size; + + if (fring->lock) pthread_mutex_unlock(&fring->mutex); + + return freed ? 1 : 0; +} + +/** Insert a new item into the circular buffer if the buffer is not full + * + * @param[in] fring to insert item into. + * @param[in] in item to insert. + * @return + * - 0 if we inserted the item. + * - -1 if there's no more space in the buffer to insert items + */ +int fr_fring_insert(fr_fring_t *fring, void *in) +{ + if (fring->lock) pthread_mutex_lock(&fring->mutex); + + if (fring->data[fring->in]) { + if (fring->lock) pthread_mutex_unlock(&fring->mutex); + + return -1; + } + + fring->data[fring->in] = in; + fring->in = (fring->in + 1) & fring->size; + + /* overwrite - out is advanced ahead of in */ + if (fring->in == fring->out) fring->out = (fring->out + 1) & fring->size; + + if (fring->lock) pthread_mutex_unlock(&fring->mutex); + + return 0; +} + +/** Remove an item from the buffer + * + * @param[in] fring to drain data from. + * @return + * - NULL if no dataents in the buffer. + * - An dataent from the buffer reparented to ctx. + */ +void *fr_fring_next(fr_fring_t *fring) +{ + void *out = NULL; + + if (fring->lock) pthread_mutex_lock(&fring->mutex); + + /* Buffer is empty */ + if (fring->out == fring->in) goto done; + + out = fring->data[fring->out]; + fring->data[fring->out] = NULL; + fring->out = (fring->out + 1) & fring->size; + +done: + if (fring->lock) pthread_mutex_unlock(&fring->mutex); + + return out; +}