*
* @copyright 2015-2017 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
*/
-#include <freeradius-devel/cbuff.h>
+#include <freeradius-devel/fring.h>
typedef enum {
DEBUGGER_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check.
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);
/*
* $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 <a.cudbardb@freeradius.org>
*/
#include <stdbool.h>
#include <stdint.h>
-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 */
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 \
+++ /dev/null
-/*
- * 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 <a.cudbardb@freeradius.org>
- */
-RCSID("$Id$")
-
-#include <freeradius-devel/libradius.h>
-#include <pthread.h>
-
-/** 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;
-}
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
#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;
{
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;
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;
}
*
* 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;
* 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);
}
}
marker->obj = (void *) obj;
- marker->cbuff = *cbuff;
+ marker->fring = *fring;
fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), 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();
--- /dev/null
+/*
+ * 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 <a.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <pthread.h>
+
+/** 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;
+}