\
typedef int (*fr_ ## _type ## _slab_free_t)(_type *elem, void *uctx); \
typedef int (*fr_ ## _type ## _slab_alloc_t)(_type *elem, void *uctx); \
+ typedef int (*fr_ ## _type ## _slab_reserve_t)(_type *elem, void *uctx); \
\
typedef struct { \
FR_DLIST_HEAD(fr_ ## _name ## _slab) reserved; \
unsigned int num_children; \
size_t child_pool_size; \
fr_ ## _type ## _slab_alloc_t alloc; \
+ fr_ ## _type ## _slab_reserve_t reserve; \
void *uctx; \
bool release_reset; \
- bool reserve_init; \
} fr_ ## _name ## _slab_list_t; \
\
typedef struct { \
_type elem; \
FR_DLIST_ENTRY(fr_ ## _name ## _slab_element) entry; \
bool in_use; \
- bool initialised; \
fr_ ## _name ## _slab_t *slab; \
fr_ ## _type ## _slab_free_t free; \
void *uctx; \
* @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] alloc Optional callback to use when allocating new elements. \
- * @param[in] uctx to pass to allocation callback. \
+ * @param[in] reserve Optional callback run on element reserving. \
+ * @param[in] uctx to pass to callbacks. \
* @param[in] release_reset Should elements be reset and children freed when the element is released.\
- * @param[in] reserve_init Should elements be initialised with the alloc function each time they are reserved.\
*/ \
static inline CC_HINT(nonnull(2)) int fr_ ## _name ## _slab_list_alloc(TALLOC_CTX *ctx, \
fr_ ## _name ## _slab_list_t **out, \
size_t num_children, \
size_t child_pool_size, \
fr_ ## _type ## _slab_alloc_t alloc, \
+ fr_ ## _type ## _slab_reserve_t reserve, \
void *uctx, \
- bool release_reset, \
- bool reserve_init) \
+ bool release_reset) \
{ \
MEM(*out = talloc_zero(ctx, fr_ ## _name ## _slab_list_t)); \
(*out)->el = el; \
(*out)->max_elements = max_elements; \
(*out)->at_max_fail = at_max_fail; \
(*out)->alloc = alloc; \
- (*out)->num_children = num_children, \
- (*out)->child_pool_size = child_pool_size, \
+ (*out)->num_children = num_children; \
+ (*out)->child_pool_size = child_pool_size; \
+ (*out)->reserve = reserve; \
(*out)->uctx = uctx; \
(*out)->release_reset = release_reset; \
- (*out)->reserve_init = reserve_init; \
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); \
\
/** Callback for talloc freeing a slab element \
* \
- * Ensure that the custom destructor is called even if \
+ * Ensure that the element reset and custom destructor is called even if \
* the element is not released before being freed. \
* Also ensure the element is removed from the relevant list. \
*/ \
new_element = prev; \
continue; \
} \
- new_element->initialised = true; \
} \
} \
slab_list->high_water_mark += fr_ ## _name ## _slab_element_num_elements(&slab->avail); \
fr_ ## _name ## _slab_remove(&slab_list->avail, slab); \
fr_ ## _name ## _slab_insert_tail(&slab_list->reserved, slab); \
} \
- if (slab_list->reserve_init && slab_list->alloc && !element->initialised) { \
- slab_list->alloc((_type *)element, slab_list->uctx); \
- element->initialised = true; \
- } \
element->in_use = true; \
slab_list->in_use++; \
} else { \
talloc_set_destructor(element, _ ## _type ## _element_free); \
if (slab_list->alloc) slab_list->alloc((_type *)element, slab_list->uctx); \
} \
+ if (slab_list->reserve) slab_list->reserve((_type *)element, slab_list->uctx); \
return (_type *)element; \
} \
\
fr_ ## _name ## _slab_insert_tail(&slab_list->avail, slab); \
} \
slab_list->in_use--; \
- element->initialised = false; \
return; \
} \
element->in_use = false; \
/*
* 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, true, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
/*
* 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, true, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
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, true, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
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, false, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
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, true, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
/** Test that a callback correctly initialises slab elements on first use
*
*/
-static void test_init_1(void)
+static void test_init(void)
{
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[2];
test_conf_t test_conf = { .initial = 10 };
int ret = -1;
- 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_conf, false, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
}
/*
- * Slab set not to reset elements, nor re-init
* Re-reserve and check element is unchanged.
*/
test_elements[1] = fr_test_slab_reserve(test_slab_list);
talloc_free(test_slab_list);
}
-/** Test that a callback correctly re-initialises slab elements on use
+/** Test that a reserve callback correctly initialises slab elements
*
*/
-static void test_init_2(void)
+static void test_reserve(void)
{
fr_test_slab_list_t *test_slab_list;
test_element_t *test_elements[2];
test_conf_t test_conf = { .initial = 10 };
int ret = -1;
- 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_conf, false, true);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
}
/*
- * Slab set re-init
- * Re-reserve and check element is reinitialised.
+ * Re-reserve and check element is re-initialised.
*/
test_elements[1] = fr_test_slab_reserve(test_slab_list);
TEST_CHECK(test_elements[1] != NULL);
talloc_free(test_slab_list);
}
+static int test_element_reserve(test_element_t *elem, void *uctx)
+{
+ test_conf_t *test_conf = uctx;
+ elem->num = test_conf->initial * 2;
+ return 0;
+}
+
+/** Test that reserve callback runs after init callback
+ *
+ */
+static void test_init_reserve(void)
+{
+ fr_test_slab_list_t *test_slab_list;
+ test_element_t *test_elements[2];
+ test_conf_t test_conf = { .initial = 10 };
+ int ret = -1;
+
+ 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);
+ TEST_CHECK(ret == 0);
+ TEST_CHECK(test_slab_list != NULL);
+
+ test_elements[0] = fr_test_slab_reserve(test_slab_list);
+ TEST_CHECK(test_elements[0] != NULL);
+ TEST_CHECK(test_elements[0] && (test_elements[0]->num == 20));
+
+ /*
+ * Change element data and release
+ */
+ if (test_elements[0]) {
+ test_elements[0]->num = 5;
+ fr_test_slab_release(test_elements[0]);
+ }
+
+ /*
+ * Re-reserve and check reset callback is run.
+ */
+ test_elements[1] = fr_test_slab_reserve(test_slab_list);
+ TEST_CHECK(test_elements[1] != NULL);
+ TEST_CHECK(test_elements[1] == test_elements[0]);
+ if (test_elements[1]) TEST_CHECK(test_elements[1]->num == 20);
+
+ talloc_free(test_slab_list);
+}
+
/** Test of clearing unused slabs
*
*/
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, true, false);
+ 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);
TEST_CHECK(ret == 0);
/*
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, true, false);
+ 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);
TEST_CHECK(ret == 0);
/*
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, true, false);
+ 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);
TEST_CHECK(ret == 0);
/*
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, true, false);
+ 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);
TEST_CHECK(ret == 0);
/*
test_element_t *test_elements[2];
int ret = -1;
- 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, false, false);
+ 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);
TEST_CHECK(ret == 0);
TEST_CHECK(test_slab_list != NULL);
{ "test_reuse_reset", test_reuse_reset },
{ "test_reuse_noreset", test_reuse_noreset },
{ "test_free", test_free },
- { "test_init_1", test_init_1 },
- { "test_init_2", test_init_2 },
+ { "test_init", test_init },
+ { "test_reserve", test_reserve },
+ { "test_init_reserve", test_init_reserve },
{ "test_clearup_1", test_clearup_1 },
{ "test_clearup_2", test_clearup_2 },
{ "test_clearup_3", test_clearup_3 },