#include <freeradius-devel/util/dlist.h>
#include <freeradius-devel/util/event.h>
+/** Tuneable parameters for slabs
+ */
+typedef struct { \
+ unsigned int elements_per_slab; //!< Number of elements to allocate per slab.
+ unsigned int min_elements; //!< Minimum number of elements to keep allocated.
+ unsigned int max_elements; //!< Maximum number of elements to allocate using slabs.
+ bool at_max_fail; //!< Should requests for additional elements fail when the
+ ///< number in use has reached max_elements.
+ size_t num_children; //!< How many child allocations are expected off each element.
+ size_t child_pool_size; //!< Size of pool space to be allocated to each element.
+ fr_time_delta_t interval; //!< Interval between slab cleanup events being fired.
+} fr_slab_config_t;
+
/** Define type specific wrapper structs for slabs and slab elements
*
* @note This macro should be used inside the header for the area of code
typedef struct { \
FR_DLIST_HEAD(fr_ ## _name ## _slab) reserved; \
FR_DLIST_HEAD(fr_ ## _name ## _slab) avail; \
- fr_time_delta_t interval; \
fr_event_list_t *el; \
fr_event_timer_t const *ev; \
- unsigned int elements_per_slab; \
- unsigned int min_elements; \
- unsigned int max_elements; \
+ fr_slab_config_t config; \
unsigned int in_use; \
unsigned int high_water_mark; \
- bool at_max_fail; \
- unsigned int num_children; \
- size_t child_pool_size; \
fr_ ## _type ## _slab_alloc_t alloc; \
fr_ ## _type ## _slab_reserve_t reserve; \
void *uctx; \
fr_ ## _name ## _slab_t *slab = NULL, *next_slab = NULL; \
unsigned int to_clear, cleared = 0; \
to_clear = (slab_list->high_water_mark - slab_list->in_use) / 2; \
- if ((slab_list->in_use + to_clear) < slab_list->min_elements) \
- to_clear = slab_list->high_water_mark - slab_list->min_elements; \
- if (to_clear < slab_list->elements_per_slab) goto finish; \
+ if ((slab_list->in_use + to_clear) < slab_list->config.min_elements) \
+ to_clear = slab_list->high_water_mark - slab_list->config.min_elements; \
+ if (to_clear < slab_list->config.elements_per_slab) goto finish; \
slab = fr_ ## _name ## _slab_head(&slab_list->avail); \
while (slab) { \
next_slab = fr_ ## _name ## _slab_next(&slab_list->avail, slab); \
to_clear -= fr_ ## _name ## _slab_element_num_elements(&slab->avail); \
fr_ ## _name ## _slab_element_talloc_free(&slab->avail); \
talloc_free(slab); \
- if (to_clear < slab_list->elements_per_slab) break; \
+ if (to_clear < slab_list->config.elements_per_slab) break; \
next: \
slab = next_slab; \
} \
slab_list->high_water_mark -= cleared; \
finish: \
- (void) fr_event_timer_in(slab_list, el, &slab_list->ev, slab_list->interval, _ ## _name ## _slab_cleanup, slab_list); \
+ (void) fr_event_timer_in(slab_list, el, &slab_list->ev, slab_list->config.interval, \
+ _ ## _name ## _slab_cleanup, slab_list); \
} \
\
/** Allocate a slab list to manage slabs of allocated memory \
* @param[in] ctx in which to allocate the slab list. \
* @param[out] out slab_list that has been allocated. \
* @param[in] el Event list in which to run clean up function. \
- * @param[in] interval Interval between cleanup events. \
- * @param[in] elements_per_slab How many elements should be allocated in each slab. \
- * @param[in] min_elements Minimum number of elements to leave allocated. \
- * @param[in] max_elements Maximun number of elements to allocate in slabs. \
- * @param[in] at_max_fail If true, no elements will be allocated beyond max_elements. \
- * @param[in] num_children Number of children expected to be allocated from each element. \
- * @param[in] child_pool_size Additional memory to allocate to each element for child allocations. \
+ * @param[in] config Slab config parameters. \
* @param[in] alloc Optional callback to use when allocating new elements. \
* @param[in] reserve Optional callback run on element reserving. \
* @param[in] uctx to pass to callbacks. \
static inline CC_HINT(nonnull(2)) int fr_ ## _name ## _slab_list_alloc(TALLOC_CTX *ctx, \
fr_ ## _name ## _slab_list_t **out, \
fr_event_list_t *el, \
- fr_time_delta_t interval, \
- unsigned int elements_per_slab, \
- unsigned int min_elements, \
- unsigned int max_elements, \
- bool at_max_fail, \
- size_t num_children, \
- size_t child_pool_size, \
+ fr_slab_config_t const *config, \
fr_ ## _type ## _slab_alloc_t alloc, \
fr_ ## _type ## _slab_reserve_t reserve, \
void *uctx, \
{ \
MEM(*out = talloc_zero(ctx, fr_ ## _name ## _slab_list_t)); \
(*out)->el = el; \
- (*out)->interval = interval; \
- (*out)->elements_per_slab = elements_per_slab; \
- (*out)->min_elements = min_elements; \
- (*out)->max_elements = max_elements; \
- (*out)->at_max_fail = at_max_fail; \
+ (*out)->config = *config; \
(*out)->alloc = alloc; \
- (*out)->num_children = num_children; \
- (*out)->child_pool_size = child_pool_size; \
(*out)->reserve = reserve; \
(*out)->uctx = uctx; \
(*out)->release_reset = release_reset; \
fr_ ## _name ## _slab_init(&(*out)->reserved); \
fr_ ## _name ## _slab_init(&(*out)->avail); \
- if (el) (void) fr_event_timer_in(*out, el, &(*out)->ev, interval, _ ## _name ## _slab_cleanup, *out); \
+ if (el) (void) fr_event_timer_in(*out, el, &(*out)->ev, config->interval, _ ## _name ## _slab_cleanup, *out); \
return 0; \
} \
\
\
slab = fr_ ## _name ## _slab_head(&slab_list->avail); \
if (!slab && ((fr_ ## _name ## _slab_num_elements(&slab_list->reserved) * \
- slab_list->elements_per_slab) < slab_list->max_elements)) { \
+ slab_list->config.elements_per_slab) < slab_list->config.max_elements)) { \
fr_ ## _name ## _slab_element_t *new_element; \
unsigned int count, elems; \
size_t elem_size; \
- elems = slab_list->elements_per_slab * (1 + slab_list->num_children); \
- elem_size = slab_list->elements_per_slab * (sizeof(fr_ ## _name ## _slab_element_t) + slab_list->child_pool_size); \
+ elems = slab_list->config.elements_per_slab * (1 + slab_list->config.num_children); \
+ elem_size = slab_list->config.elements_per_slab * (sizeof(fr_ ## _name ## _slab_element_t) + \
+ slab_list->config.child_pool_size); \
MEM(slab = talloc_zero_pooled_object(slab_list, fr_ ## _name ## _slab_t, elems, elem_size)); \
fr_ ## _name ## _slab_element_init(&slab->avail); \
fr_ ## _name ## _slab_element_init(&slab->reserved); \
fr_ ## _name ## _slab_insert_head(&slab_list->avail, slab); \
slab->list = slab_list; \
- for (count = 0; count < slab_list->elements_per_slab; count++) { \
- if (slab_list->num_children > 0) { \
+ for (count = 0; count < slab_list->config.elements_per_slab; count++) { \
+ if (slab_list->config.num_children > 0) { \
MEM(new_element = talloc_zero_pooled_object(slab, fr_ ## _name ## _slab_element_t, \
- slab_list->num_children, \
- slab_list->child_pool_size)); \
+ slab_list->config.num_children, \
+ slab_list->config.child_pool_size)); \
} else { \
MEM(new_element = talloc_zero(slab, fr_ ## _name ## _slab_element_t)); \
} \
} \
slab_list->high_water_mark += fr_ ## _name ## _slab_element_num_elements(&slab->avail); \
} \
- if (!slab && slab_list->at_max_fail) return NULL; \
+ if (!slab && slab_list->config.at_max_fail) return NULL; \
if (slab) element = fr_ ## _name ## _slab_element_pop_head(&slab->avail); \
if (element) { \
fr_ ## _name ## _slab_element_insert_tail(&slab->reserved, element); \
int initial;
} test_conf_t;
+fr_slab_config_t def_slab_config = (fr_slab_config_t) {
+ .elements_per_slab = 2,
+ .min_elements = 1,
+ .max_elements = 4,
+ .at_max_fail = false,
+ .num_children = 0,
+ .child_pool_size = 0,
+ .interval.value = 1 * NSEC
+};
+
static int test_element_free(test_element_t *elem, void *uctx)
{
test_uctx_t *test_uctx = uctx;
/*
* Each slab will contain 2 elements, maximum of 4 elements allocated from slabs.
*/
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 2, 1, 4, false, 0, 0, NULL, NULL, NULL, true);
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &def_slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[5];
int ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
/*
* Each slab will contain 2 elements, maximum of 4 elements allocated from slabs.
*/
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 2, 1, 4, true, 0, 0, NULL, NULL, NULL, true);
+ slab_config.at_max_fail = true;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
test_uctx_t test_uctx;
int ret = -1;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 2, 1, 4, false, 0, 0, NULL, NULL, NULL, true);
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &def_slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
test_uctx_t test_uctx;
int ret = -1;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 2, 1, 4, false, 0, 0, NULL, NULL, NULL, false);
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &def_slab_config, NULL, NULL, NULL, false);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
test_uctx_t test_uctx;
int ret = -1;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 2, 1, 4, false, 0, 0, NULL, NULL, NULL, true);
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &def_slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
test_element_t *test_elements[2];
test_conf_t test_conf = { .initial = 10 };
int ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 1, 1, 4, false, 0, 0, test_element_alloc, NULL, &test_conf, false);
+ slab_config.elements_per_slab = 1;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &slab_config, test_element_alloc, NULL, &test_conf, false);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
test_element_t *test_elements[2];
test_conf_t test_conf = { .initial = 10 };
int ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 1, 1, 4, false, 0, 0, NULL, test_element_alloc, &test_conf, false);
+ slab_config.elements_per_slab = 1;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &slab_config, NULL, test_element_alloc, &test_conf, false);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
test_element_t *test_elements[2];
test_conf_t test_conf = { .initial = 10 };
int ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 1, 1, 4, false, 0, 0, test_element_alloc, test_element_reserve, &test_conf, false);
+ slab_config.elements_per_slab = 1;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &slab_config, test_element_alloc, test_element_reserve, &test_conf, false);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[6];
int i, events, ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
el = fr_event_list_alloc(ctx, NULL, NULL);
fr_event_list_set_time_func(el, test_time);
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, fr_time_delta_from_sec(1), 2, 1, 6, false, 0, 0, NULL, NULL, NULL, true);
+ slab_config.max_elements = 6;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, &slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[20];
int i, events, ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
el = fr_event_list_alloc(ctx, NULL, NULL);
fr_event_list_set_time_func(el, test_time);
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, fr_time_delta_from_sec(1), 2, 16, 20, false, 0, 0, NULL, NULL, NULL, true);
+ slab_config.min_elements = 16;
+ slab_config.max_elements = 20;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, &slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[20];
int i, events, ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
el = fr_event_list_alloc(ctx, NULL, NULL);
fr_event_list_set_time_func(el, test_time);
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, fr_time_delta_from_sec(1), 2, 0, 20, false, 0, 0, NULL, NULL, NULL, true);
+ slab_config.min_elements = 0;
+ slab_config.max_elements = 20;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, &slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[20];
int i, events, ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
el = fr_event_list_alloc(ctx, NULL, NULL);
fr_event_list_set_time_func(el, test_time);
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, fr_time_delta_from_sec(1), 2, 0, 20, false, 0, 0, NULL, NULL, NULL, true);
+ slab_config.min_elements = 0;
+ slab_config.max_elements = 20;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, el, &slab_config, NULL, NULL, NULL, true);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[2];
int ret = -1;
+ fr_slab_config_t slab_config = def_slab_config;
- ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, fr_time_delta_from_sec(1), 2, 1, 2, true, 1, 128, NULL, NULL, NULL, false);
+ slab_config.max_elements = 2;
+ slab_config.num_children = 1;
+ slab_config.child_pool_size = 128;
+ ret = fr_test_slab_list_alloc(NULL, &test_slab_list, NULL, &slab_config, NULL, NULL, NULL, false);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
if (!test_slab_list) return;