]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add reserve callback to slab allocator
authorNick Porter <nick@portercomputing.co.uk>
Fri, 3 Feb 2023 17:29:07 +0000 (17:29 +0000)
committerNick Porter <nick@portercomputing.co.uk>
Thu, 9 Feb 2023 12:13:32 +0000 (12:13 +0000)
Allow for differentiation between alloc callback (just used on first
allocation) and reserve (used each time an element is reserved)

src/lib/util/slab.h
src/lib/util/slab_tests.c

index c2cb61efdfde1b86a76a5bdcd6a68053d438548e..8783dc0c4e6947e89ca28edf609d8b1bc6b40003 100644 (file)
@@ -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; \
index 871a048c7eb162eba662fc1071ce3d5e575801c5..13a2ed2d57f23b283d3c0b694e919c093a5c837a 100644 (file)
@@ -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 },