From: Nick Porter Date: Fri, 3 Feb 2023 17:29:07 +0000 (+0000) Subject: Add reserve callback to slab allocator X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b89733f4b455091ab176ba0152f180de5f3fac9d;p=thirdparty%2Ffreeradius-server.git Add reserve callback to slab allocator Allow for differentiation between alloc callback (just used on first allocation) and reserve (used each time an element is reserved) --- diff --git a/src/lib/util/slab.h b/src/lib/util/slab.h index c2cb61efdfd..8783dc0c4e6 100644 --- a/src/lib/util/slab.h +++ b/src/lib/util/slab.h @@ -54,6 +54,7 @@ extern "C" { \ 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; \ @@ -70,9 +71,9 @@ extern "C" { 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 { \ @@ -87,7 +88,6 @@ extern "C" { _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; \ @@ -152,9 +152,9 @@ extern "C" { * @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, \ @@ -167,9 +167,9 @@ extern "C" { 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; \ @@ -179,11 +179,11 @@ extern "C" { (*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); \ @@ -192,7 +192,7 @@ extern "C" { \ /** 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. \ */ \ @@ -264,7 +264,6 @@ extern "C" { new_element = prev; \ continue; \ } \ - new_element->initialised = true; \ } \ } \ slab_list->high_water_mark += fr_ ## _name ## _slab_element_num_elements(&slab->avail); \ @@ -277,10 +276,6 @@ extern "C" { 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 { \ @@ -288,6 +283,7 @@ extern "C" { 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; \ } \ \ @@ -332,7 +328,6 @@ extern "C" { fr_ ## _name ## _slab_insert_tail(&slab_list->avail, slab); \ } \ slab_list->in_use--; \ - element->initialised = false; \ return; \ } \ element->in_use = false; \ diff --git a/src/lib/util/slab_tests.c b/src/lib/util/slab_tests.c index 871a048c7eb..13a2ed2d57f 100644 --- a/src/lib/util/slab_tests.c +++ b/src/lib/util/slab_tests.c @@ -52,7 +52,7 @@ static void test_alloc(void) /* * 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); @@ -123,7 +123,7 @@ static void test_alloc_fail(void) /* * 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); @@ -158,7 +158,7 @@ static void test_reuse_reset(void) 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); @@ -219,7 +219,7 @@ static void test_reuse_noreset(void) 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); @@ -272,7 +272,7 @@ static void test_free(void) 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); @@ -300,14 +300,14 @@ static int test_element_alloc(test_element_t *elem, void *uctx) /** 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); @@ -324,7 +324,6 @@ static void test_init_1(void) } /* - * 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); @@ -335,17 +334,17 @@ static void test_init_1(void) 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); @@ -362,8 +361,7 @@ static void test_init_2(void) } /* - * 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); @@ -373,6 +371,50 @@ static void test_init_2(void) 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 * */ @@ -387,7 +429,7 @@ static void test_clearup_1(void) 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); /* @@ -438,7 +480,7 @@ static void test_clearup_2(void) 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); /* @@ -499,7 +541,7 @@ static void test_clearup_3(void) 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); /* @@ -589,7 +631,7 @@ static void test_realloc(void) 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); /* @@ -642,7 +684,7 @@ static void test_child_alloc(void) 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); @@ -677,8 +719,9 @@ TEST_LIST = { { "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 },