]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move unlang_t to use dlists
authorAlan T. DeKok <aland@freeradius.org>
Sun, 27 Jul 2025 15:06:38 +0000 (11:06 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 27 Jul 2025 15:06:38 +0000 (11:06 -0400)
15 files changed:
src/lib/unlang/call.c
src/lib/unlang/caller.c
src/lib/unlang/catch.c
src/lib/unlang/compile.c
src/lib/unlang/condition.c
src/lib/unlang/edit.c
src/lib/unlang/interpret.c
src/lib/unlang/load_balance.c
src/lib/unlang/map.c
src/lib/unlang/module.c
src/lib/unlang/parallel.c
src/lib/unlang/subrequest.c
src/lib/unlang/switch.c
src/lib/unlang/tmpl.c
src/lib/unlang/unlang_priv.h

index f6267ea2594ecf3774b967057aca2086a081f535..320948351bf3dbe6876e89e7cf882a9a2bbd7d66 100644 (file)
@@ -129,7 +129,7 @@ static unlang_action_t unlang_call_frame_init(unlang_result_t *p_result, request
         *      DIE DIE DIE DIE DIE DIE DIE DIE DIE
         *      DIE DIE DIE.
         */
-       if (!g->children) {
+       if (unlang_list_empty(&g->children)) {
                frame_repeat(frame, unlang_call_resume);
        } else {
                frame_repeat(frame, unlang_call_children);
@@ -190,6 +190,8 @@ unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request,
                .attr_packet_type = attr_packet_type
        };
 
+       unlang_group_type_init(&c->group.self, NULL, UNLANG_TYPE_CALL);
+
        /*
         *      Push a new call frame onto the stack
         */
index 30e187d22cc5ce7f386ff5b5dd5e75357cacce50..b6a38d7b55ccc47152414747a9aed935a7c767db 100644 (file)
@@ -35,7 +35,7 @@ static unlang_action_t unlang_caller(unlang_result_t *p_result, request_t *reque
        unlang_group_t                  *g = unlang_generic_to_group(frame->instruction);
        unlang_caller_t                 *gext = unlang_group_to_caller(g);
 
-       fr_assert(g->num_children > 0); /* otherwise the compilation is broken */
+       fr_assert(!unlang_list_empty(&g->children)); /* otherwise the compilation is broken */
 
        /*
         *      No parent, or the dictionaries don't match.  Ignore it.
@@ -131,7 +131,7 @@ static unlang_t *unlang_compile_caller(unlang_t *parent, unlang_compile_ctx_t *u
                talloc_steal(gext, dict_ref);
        }
 
-       if (!g->num_children) {
+       if (unlang_list_empty(&g->children)) {
                talloc_free(c);
                return UNLANG_IGNORE;
        }
index 70ef78fb7dd8c6b5878ad275e4acd2d4737c6714..f8fdd465ecd1962038897b3e5505b00453461cdb 100644 (file)
@@ -30,19 +30,17 @@ RCSID("$Id$")
 
 static unlang_action_t catch_skip_to_next(UNUSED unlang_result_t *p_result, UNUSED request_t *request, unlang_stack_frame_t *frame)
 {
-       unlang_t                *unlang;
+       unlang_t const *unlang = frame->instruction;
 
        fr_assert(frame->instruction->type == UNLANG_TYPE_CATCH);
 
-       for (unlang = frame->instruction->next;
-            unlang != NULL;
-            unlang = unlang->next) {
-               if (unlang->type == UNLANG_TYPE_CATCH) continue;
-
-               break;
+       while ((unlang = unlang_list_next(unlang->list, unlang)) != NULL) {
+               if (unlang->type != UNLANG_TYPE_CATCH) {
+                       return frame_set_next(frame, unlang);
+               }
        }
 
-       return frame_set_next(frame, unlang);
+       return frame_set_next(frame, NULL);
 }
 
 static unlang_action_t unlang_catch(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
@@ -67,23 +65,17 @@ static unlang_action_t unlang_catch(UNUSED unlang_result_t *p_result, request_t
  */
 unlang_action_t unlang_interpret_skip_to_catch(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
 {
-       unlang_t                *unlang;
+       unlang_t const          *unlang;
        rlm_rcode_t             rcode = unlang_interpret_rcode(request);
 
        fr_assert(frame->instruction->type == UNLANG_TYPE_TRY);
 
-       /*
-        *      'try' at the end of a block without 'catch' should have been caught by the compiler.
-        */
-       fr_assert(frame->instruction->next);
-
-       for (unlang = frame->instruction->next;
+       for (unlang = unlang_list_next(frame->instruction->list, frame->instruction);
             unlang != NULL;
-            unlang = unlang->next) {
+            unlang = unlang_list_next(unlang->list, unlang)) {
                unlang_catch_t const *c;
 
                if (unlang->type != UNLANG_TYPE_CATCH) {
-               not_caught:
                        RDEBUG3("No catch section for %s",
                                fr_table_str_by_value(mod_rcode_table, rcode, "<invalid>"));
                        return frame_set_next(frame, unlang);
@@ -92,11 +84,14 @@ unlang_action_t unlang_interpret_skip_to_catch(UNUSED unlang_result_t *p_result,
                if (rcode >= RLM_MODULE_NUMCODES) continue;
 
                c = unlang_generic_to_catch(unlang);
-               if (c->catching[rcode]) break;
+               if (c->catching[rcode]) {
+                       return frame_set_next(frame, unlang);
+               }
        }
-       if (!unlang) goto not_caught;
 
-       return frame_set_next(frame, unlang);
+       RDEBUG3("No catch section for %s",
+               fr_table_str_by_value(mod_rcode_table, rcode, "<invalid>"));
+       return frame_set_next(frame, NULL);
 }
 
 static int catch_argv(CONF_SECTION *cs, unlang_catch_t *ca, char const *name)
index e9772e7e521a5564f78d0583e4a313ef54ab0650..fb70c8231b40db4a91870253e84dc4feee329c76 100644 (file)
@@ -240,12 +240,11 @@ bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
 
 static void unlang_dump(unlang_t *instruction, int depth)
 {
-       unlang_t *c;
        unlang_group_t *g;
        map_t *map;
        char buffer[1024];
 
-       for (c = instruction; c != NULL; c = c->next) {
+       unlang_list_foreach(instruction->list, c) {
                switch (c->type) {
                case UNLANG_TYPE_NULL:
                case UNLANG_TYPE_CHILD_REQUEST:
@@ -322,9 +321,8 @@ static void unlang_dump(unlang_t *instruction, int depth)
                case UNLANG_TYPE_TRANSACTION:
                case UNLANG_TYPE_TRY:
                case UNLANG_TYPE_CATCH: /* @todo - print out things we catch, too */
-                       g = unlang_generic_to_group(c);
                        DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name);
-                       unlang_dump(g->children, depth + 1);
+                       unlang_dump(c, depth + 1);
                        DEBUG("%.*s}", depth, unlang_spaces);
                        break;
 
@@ -464,15 +462,13 @@ unlang_group_t *unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang
                                                         op->pool_headers, op->pool_len);
        if (!g) return NULL;
 
-       g->children = NULL;
-       g->tail = &g->children;
        g->cs = cs;
 
        c = unlang_group_to_generic(g);
-       c->parent = parent;
-       c->type = type;
        c->ci = CF_TO_ITEM(cs);
 
+       unlang_group_type_init(c, parent, type);
+
        return g;
 }
 
@@ -644,11 +640,9 @@ static unlang_t *compile_edit_section(unlang_t *parent, unlang_compile_ctx_t *un
        if (!edit) return NULL;
 
        c = out = unlang_edit_to_generic(edit);
-       c->parent = parent;
-       c->next = NULL;
+       unlang_type_init(c, parent, UNLANG_TYPE_EDIT);
        c->name = cf_section_name1(cs);
        c->debug_name = c->name;
-       c->type = UNLANG_TYPE_EDIT;
        c->ci = CF_TO_ITEM(cs);
 
        map_list_init(&edit->maps);
@@ -786,11 +780,9 @@ static unlang_t *compile_edit_pair(unlang_t *parent, unlang_compile_ctx_t *unlan
        if (!edit) return NULL;
 
        c = out = unlang_edit_to_generic(edit);
-       c->parent = parent;
-       c->next = NULL;
+       unlang_type_init(c, parent, UNLANG_TYPE_EDIT);
        c->name = cf_pair_attr(cp);
        c->debug_name = c->name;
-       c->type = UNLANG_TYPE_EDIT;
        c->ci = CF_TO_ITEM(cp);
 
        map_list_init(&edit->maps);
@@ -1489,11 +1481,7 @@ unlang_t *unlang_compile_children(unlang_group_t *g, unlang_compile_ctx_t *unlan
                 */
                fr_assert(g == talloc_parent(single));
                fr_assert(single->parent == unlang_group_to_generic(g));
-               fr_assert(!single->next);
-
-               *g->tail = single;
-               g->tail = &single->next;
-               g->num_children++;
+               unlang_list_insert_tail(&g->children, single);
 
                /*
                 *      If it's not possible to execute statement
@@ -1567,11 +1555,9 @@ static unlang_t *compile_tmpl(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx
 
        MEM(ut = talloc_zero(parent, unlang_tmpl_t));
        c = unlang_tmpl_to_generic(ut);
-       c->parent = parent;
-       c->next = NULL;
+       unlang_type_init(c, parent, UNLANG_TYPE_TMPL);
        c->name = p;
        c->debug_name = c->name;
-       c->type = UNLANG_TYPE_TMPL;
        c->ci = CF_TO_ITEM(cp);
 
        RULES_VERIFY(unlang_ctx->rules);
@@ -1832,12 +1818,9 @@ static unlang_t *compile_module(unlang_t *parent, unlang_compile_ctx_t *unlang_c
        }
 
        c = unlang_module_to_generic(m);
-       c->parent = parent;
-       c->next = NULL;
-
+       unlang_type_init(c, parent, UNLANG_TYPE_MODULE);
        c->name = talloc_typed_strdup(c, name);
        c->debug_name = c->name;
-       c->type = UNLANG_TYPE_MODULE;
        c->ci = ci;
 
        /*
@@ -2472,10 +2455,8 @@ static void unlang_perf_dump(fr_log_t *log, unlang_t const *instruction, int dep
        fr_log(log, L_DBG, file, line, "count=%" PRIu64 " cpu_time=%" PRId64 " yielded_time=%" PRId64 ,
               t->use_count, fr_time_delta_unwrap(t->tracking.running_total), fr_time_delta_unwrap(t->tracking.waiting_total));
 
-       if (g->children) {
-               unlang_t *child;
-
-               for (child = g->children; child != NULL; child = child->next) {
+       if (!unlang_list_empty(&g->children)) {
+               unlang_list_foreach(&g->children, child) {
                        unlang_perf_dump(log, child, depth + 1);
                }
        }
index bccda50f6ba70de66f8134cb3e50dce15be0d34a..6219be2e1109969493f0083d6d75200cdb061a0d 100644 (file)
@@ -38,6 +38,7 @@ static unlang_action_t unlang_if_resume(unlang_result_t *p_result, request_t *re
        unlang_frame_state_cond_t       *state = talloc_get_type_abort(frame->state, unlang_frame_state_cond_t);
        fr_value_box_t                  *box = fr_value_box_list_head(&state->out);
        bool                            value;
+       unlang_t const                  *unlang;
 
        /*
         *      Something in the conditional evaluation failed.
@@ -71,12 +72,22 @@ static unlang_action_t unlang_if_resume(unlang_result_t *p_result, request_t *re
         *      Tell the main interpreter to skip over the else /
         *      elsif blocks, as this "if" condition was taken.
         */
-       while (frame->next &&
-              ((frame->next->type == UNLANG_TYPE_ELSE) ||
-               (frame->next->type == UNLANG_TYPE_ELSIF))) {
-               frame->next = frame->next->next;
+       for (unlang = frame->next;
+            unlang != NULL;
+            unlang = unlang_list_next(unlang->list, unlang)) {
+               if ((unlang->type == UNLANG_TYPE_ELSE) ||
+                   (unlang->type == UNLANG_TYPE_ELSIF)) {
+                       continue;
+               }
+
+               break;
        }
 
+       /*
+        *      Do NOT call frame_set_next(), as that will clean up the current frame.
+        */
+       frame->next = unlang;
+
        /*
         *      We took the "if".  Go recurse into its' children.
         */
index 34a6c47a9bbc8cd7fb917dada9723b4baca9b411..38fd839326c6e09ed6c9b839b81d11fde662c9a8 100644 (file)
@@ -1728,6 +1728,8 @@ int unlang_edit_push(request_t *request, bool *success, fr_edit_list_t *el, map_
        *edit = (unlang_edit_t) {
                .self = edit_instruction,
        };
+
+       unlang_type_init(&edit->self, NULL, UNLANG_TYPE_EDIT);
        map_list_init(&edit->maps);
 
        /*
index f4efc435e64cc925022dccf48b97e72746356a71..ea9d112b7a5cc6482b921bc383b5931d3a7c37a2 100644 (file)
@@ -319,9 +319,9 @@ int unlang_interpret_push(unlang_result_t *p_result, request_t *request,
 
        frame->instruction = instruction;
 
-       if (do_next_sibling) {
+       if (do_next_sibling && instruction->list) {
                fr_assert(instruction != NULL);
-               frame->next = instruction->next;
+               frame->next = unlang_list_next(instruction->list, instruction);
        }
        /* else frame->next MUST be NULL */
 
@@ -398,12 +398,12 @@ unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, reques
         *      top-level 'recv Access-Request' etc.  Which can exist,
         *      and can be empty.
         */
-       if (!g->children) {
+       if (unlang_list_empty(&g->children)) {
                RDEBUG2("... ignoring empty subsection ...");
                return UNLANG_ACTION_EXECUTE_NEXT;
        }
 
-       if (unlang_interpret_push(p_result, request, g->children,
+       if (unlang_interpret_push(p_result, request, unlang_list_head(&g->children),
                                  FRAME_CONF(default_rcode, UNLANG_SUB_FRAME), do_next_sibling) < 0) {
                return UNLANG_ACTION_STOP_PROCESSING;
        }
index 55891ee3db1bac65cb5841c553c2304300a346b7..fa4fd1acfe13e44197eca4bdba3ea9f88c568c53 100644 (file)
@@ -69,8 +69,8 @@ static unlang_action_t unlang_load_balance_next(unlang_result_t *p_result, reque
         *      We finished the previous child, and it failed.  Go to the next one.  If we fall off of the
         *      end, loop around to the next one.
         */
-       redundant->child = redundant->child->next;
-       if (!redundant->child) redundant->child = g->children;
+       redundant->child = unlang_list_next(&g->children, redundant->child);
+       if (!redundant->child) redundant->child = unlang_list_head(&g->children);
 
        /*
         *      We looped back to the start.  Return whatever results we had from the last child.
@@ -108,7 +108,7 @@ static unlang_action_t unlang_redundant(unlang_result_t *p_result, request_t *re
        /*
         *      Start at the first child, and then continue from there.
         */
-       redundant->start = g->children;
+       redundant->start = unlang_list_head(&g->children);
 
        frame->process = unlang_load_balance_next;
        return unlang_load_balance_next(p_result, request, frame);
@@ -119,15 +119,14 @@ static unlang_action_t unlang_load_balance(unlang_result_t *p_result, request_t
        unlang_frame_state_redundant_t  *redundant;
        unlang_group_t                  *g = unlang_generic_to_group(frame->instruction);
        unlang_load_balance_t           *gext = NULL;
-       unlang_t                        *child;
 
        uint32_t                        count = 0;
 
 #ifdef STATIC_ANALYZER
-       if (!g || !g->num_children) return UNLANG_ACTION_STOP_PROCESSING;
+       if (!g || unlang_list_empty(&g->children)) return UNLANG_ACTION_STOP_PROCESSING;
 #else
        fr_assert(g != NULL);
-       fr_assert(g->num_children);
+       fr_assert(!unlang_list_empty(&g->children));
 #endif
 
        gext = unlang_group_to_load_balance(g);
@@ -154,7 +153,7 @@ static unlang_action_t unlang_load_balance(unlang_result_t *p_result, request_t
 
                        fr_assert(fr_type_is_leaf(vp->vp_type));
 
-                       start = fr_value_box_hash(&vp->data) % g->num_children;
+                       start = fr_value_box_hash(&vp->data) % unlang_list_num_elements(&g->children);
 
                } else {
                        uint8_t *octets = NULL;
@@ -168,23 +167,25 @@ static unlang_action_t unlang_load_balance(unlang_result_t *p_result, request_t
 
                        hash = fr_hash(octets, slen);
 
-                       start = hash % g->num_children;
+                       start = hash % unlang_list_num_elements(&g->children);
                }
 
                RDEBUG3("load-balance starting at child %d", (int) start);
 
                count = 0;
-               for (child = redundant->start = g->children; child != NULL; child = child->next) {
-                       count++;
+               unlang_list_foreach(&g->children, child) {
                        if (count == start) {
                                redundant->start = child;
                                break;
                        }
+
+                       count++;
                }
+               fr_assert(redundant->start != NULL);
 
        } else {
        randomly_choose:
-               count = 0;
+               count = 1;
 
                /*
                 *      Choose a child at random.
@@ -200,12 +201,15 @@ static unlang_action_t unlang_load_balance(unlang_result_t *p_result, request_t
                 *      for this load-balance section.  So for now,
                 *      just pick a random child.
                 */
-               for (child = redundant->start = g->children; child != NULL; child = child->next) {
-                       count++;
+               unlang_list_foreach(&g->children, child) {
                        if ((count * (fr_rand() & 0xffffff)) < (uint32_t) 0x1000000) {
                                redundant->start = child;
                        }
+                       count++;
                }
+
+               fr_assert(redundant->start != NULL);
+
        }
 
        fr_assert(redundant->start != NULL);
index 72adf8e442bb0234edd6482141e9cdf52adfa237..cc6bc1fef21afcd2ed90fbe6c6b8d21cc52d0a16 100644 (file)
@@ -278,8 +278,8 @@ static unlang_action_t unlang_update_state_init(unlang_result_t *p_result, reque
         */
        MEM(frame->state = update_state = talloc_zero_pooled_object(request->stack, unlang_frame_state_update_t,
                                                                    (sizeof(map_t) +
-                                                                   (sizeof(tmpl_t) * 2) + 128),
-                                                                   g->num_children));  /* 128 is for string buffers */
+                                                                   (sizeof(tmpl_t) * 2) + 128),        /* 128 is for string buffers */
+                                                                   unlang_list_num_elements(&g->children)));
 
        fr_dcursor_init(&update_state->maps, &gext->map.head);
        fr_value_box_list_init(&update_state->lhs_result);
index 46fd9bdbe021505dfd78b25e65c5ac8af433c9a3..22e706f2bd82a8a8638ce93bbccf9f5be2fe1280 100644 (file)
@@ -75,6 +75,7 @@ int unlang_module_push(unlang_result_t *p_result, request_t *request,
                        }
                }
        };
+       unlang_type_init(&mc->self, NULL, UNLANG_TYPE_MODULE);
 
        /*
         *      Push a new module frame onto the stack
index 4b50b54271085e473d5dfed12693e95f78eab431..05b0d28fec3bd95e17224e99c8e2107a444d09cd 100644 (file)
@@ -204,10 +204,13 @@ static unlang_action_t unlang_parallel(unlang_result_t *p_result, request_t *req
        unlang_group_t                  *g;
        unlang_parallel_t               *gext;
        unlang_parallel_state_t         *state;
-       int                     i;
+       int                             i;
+       size_t                          num_children;
 
        g = unlang_generic_to_group(frame->instruction);
-       if (!g->num_children) RETURN_UNLANG_NOOP;
+
+       num_children = unlang_list_num_elements(&g->children);
+       if (num_children == 0) RETURN_UNLANG_NOOP;
 
        gext = unlang_group_to_parallel(g);
 
@@ -216,9 +219,9 @@ static unlang_action_t unlang_parallel(unlang_result_t *p_result, request_t *req
         */
        MEM(frame->state = state = _talloc_zero_pooled_object(request,
                                                              sizeof(unlang_parallel_state_t) +
-                                                             (sizeof(state->children[0]) * g->num_children),
+                                                             (sizeof(state->children[0]) * num_children),
                                                              "unlang_parallel_state_t",
-                                                             g->num_children,
+                                                             num_children,
                                                              (talloc_array_length(request->name) * 2)));
        if (!state) {
                return UNLANG_ACTION_FAIL;
@@ -228,12 +231,14 @@ static unlang_action_t unlang_parallel(unlang_result_t *p_result, request_t *req
        state->result = UNLANG_RESULT_NOT_SET;
        state->detach = gext->detach;
        state->clone = gext->clone;
-       state->num_children = g->num_children;
+       state->num_children = unlang_list_num_elements(&g->children);
 
        /*
         *      Initialize all of the children.
         */
-       for (i = 0, instruction = g->children; instruction != NULL; i++, instruction = instruction->next) {
+       for (i = 0, instruction = unlang_list_head(&g->children);
+            instruction != NULL;
+            i++, instruction = unlang_list_next(&g->children, instruction)) {
                request_t                       *child;
                unlang_result_t                 *child_result;
 
@@ -398,10 +403,10 @@ static unlang_t *unlang_compile_parallel(unlang_t *parent, unlang_compile_ctx_t
        if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
 
        /*
-        *      Parallel sections can create empty children, if the
-        *      admin demands it.  Otherwise, the principle of least
-        *      surprise is to copy the whole request, reply, and
-        *      config items.
+        *      Parallel sections can create empty child requests, if
+        *      the admin demands it.  Otherwise, the principle of
+        *      least surprise is to copy the whole request, reply,
+        *      and config items.
         */
        name2 = cf_section_name2(cs);
        if (name2) {
index 6e5fb5b11cecccd91ca94967511bfa63d6f51e26..154e10d8139176388d6775f4d5f3badf8884b50d 100644 (file)
@@ -186,7 +186,7 @@ static unlang_action_t unlang_subrequest_init(unlang_result_t *p_result, request
         *      Initialize the state
         */
        g = unlang_generic_to_group(frame->instruction);
-       if (!g->num_children) RETURN_UNLANG_NOOP;
+       if (unlang_list_empty(&g->children)) RETURN_UNLANG_NOOP;
 
        gext = unlang_group_to_subrequest(g);
        child = unlang_io_subrequest_alloc(request, gext->dict, UNLANG_DETACHABLE);
@@ -263,7 +263,7 @@ static unlang_action_t unlang_subrequest_init(unlang_result_t *p_result, request
         *      Push the first instruction the child's
         *      going to run.
         */
-       if (unlang_interpret_push(NULL, child, g->children,
+       if (unlang_interpret_push(NULL, child, unlang_list_head(&g->children),
                                  FRAME_CONF(RLM_MODULE_NOT_SET, UNLANG_SUB_FRAME),
                                  UNLANG_NEXT_SIBLING) < 0) goto fail;
 
@@ -527,6 +527,8 @@ static unlang_t *unlang_compile_subrequest(unlang_t *parent, unlang_compile_ctx_
 
        tmpl_t                          *vpt = NULL, *src_vpt = NULL, *dst_vpt = NULL;
 
+       if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
+
        /*
         *      subrequest { ... }
         *
index 2673bafaf36f9201a33d58830776fd49fdaee963..ca5f0cb846d8ad582fc3c6e315426ab9778c398c 100644 (file)
@@ -124,7 +124,7 @@ static unlang_action_t unlang_case(unlang_result_t *p_result, request_t *request
 {
        unlang_group_t          *g = unlang_generic_to_group(frame->instruction);
 
-       if (!g->children) RETURN_UNLANG_NOOP;
+       if (unlang_list_empty(&g->children)) RETURN_UNLANG_NOOP;
 
        return unlang_group(p_result, request, frame);
 }
@@ -509,9 +509,7 @@ static unlang_t *unlang_compile_switch(unlang_t *parent, unlang_compile_ctx_t *u
                        goto error;
                }
 
-               *g->tail = single;
-               g->tail = &single->next;
-               g->num_children++;
+               unlang_list_insert_tail(&g->children, single);
        }
 
        return c;
index 02a24f8d8e67abd185b399b43e7717c65c9c0a60..c1bf1062c16337698665f576a359c1136ecf99ad 100644 (file)
@@ -316,6 +316,7 @@ int unlang_tmpl_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_li
                .self =  p_result ? tmpl_instruction_fail : tmpl_instruction_return,
                .tmpl = tmpl
        };
+       unlang_type_init(&ut->self, NULL, UNLANG_TYPE_TMPL);
 
        /*
         *      Push a new tmpl frame onto the stack
index 95bb2105a8caaaa9fcf5ed0a89804113e6d128c9..35840bf7bcb06accc31f5c28c03304ccb71de056 100644 (file)
@@ -30,6 +30,7 @@
 #include <freeradius-devel/server/modpriv.h>
 #include <freeradius-devel/server/time_tracking.h>
 #include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/dlist.h>
 #include <freeradius-devel/unlang/base.h>
 #include <freeradius-devel/unlang/map.h>
 #include <freeradius-devel/io/listen.h>
@@ -117,6 +118,9 @@ DIAG_ON(attributes)
 typedef struct unlang_s unlang_t;
 typedef struct unlang_stack_frame_s unlang_stack_frame_t;
 
+FR_DLIST_TYPES(unlang_list)
+FR_DLIST_TYPEDEFS(unlang_list, unlang_list_t, unlang_entry_t)
+
 /** A node in a graph of #unlang_op_t (s) that we execute
  *
  * The interpreter acts like a turing machine, with #unlang_t nodes forming the tape
@@ -130,7 +134,8 @@ typedef struct unlang_stack_frame_s unlang_stack_frame_t;
  */
 struct unlang_s {
        unlang_t                *parent;        //!< Previous node.
-       unlang_t                *next;          //!< Next node (executed on #UNLANG_ACTION_EXECUTE_NEXT et al).
+       unlang_list_t           *list;          //!< so we have fewer run-time dereferences
+       unlang_entry_t          entry;          //!< next / prev entries
        char const              *name;          //!< Unknown...
        char const              *debug_name;    //!< Printed in log messages when the node is executed.
        unlang_type_t           type;           //!< The specialisation of this node.
@@ -140,6 +145,9 @@ struct unlang_s {
        unlang_mod_actions_t    actions;        //!< Priorities, etc. for the various return codes.
 };
 
+FR_DLIST_FUNCS(unlang_list, unlang_t, entry)
+#define unlang_list_foreach(_list_head, _iter) fr_dlist_foreach(unlang_list_dlist_head(_list_head), unlang_t, _iter)
+
 typedef struct {
        fr_dict_t               *dict;          //!< our dictionary
        fr_dict_attr_t const    *root;          //!< the root of our dictionary
@@ -152,11 +160,9 @@ typedef struct {
  */
 typedef struct {
        unlang_t                self;
-       unlang_t                *children;      //!< Children beneath this group.  The body of an if
-                                               //!< section for example.
-       unlang_t                **tail;         //!< pointer to the tail which gets updated
+
        CONF_SECTION            *cs;
-       int                     num_children;
+       unlang_list_t           children;
 
        unlang_variable_t       *variables;     //!< rarely used, so we don't usually need it
 } unlang_group_t;
@@ -702,7 +708,7 @@ static inline void frame_next(unlang_stack_t *stack, unlang_stack_frame_t *frame
 
        if (!frame->instruction) return;        /* No siblings, need to pop instead */
 
-       frame->next = frame->instruction->next;
+       frame->next = unlang_list_next(frame->instruction->list, frame->instruction);
 
        /*
         *      We _may_ want to take a new frame->p_result value in future but
@@ -768,7 +774,7 @@ static inline void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t pr
        frame->process = process;
 }
 
-static inline unlang_action_t frame_set_next(unlang_stack_frame_t *frame, unlang_t *unlang)
+static inline unlang_action_t frame_set_next(unlang_stack_frame_t *frame, unlang_t const *unlang)
 {
        /*
         *      We're skipping the remaining siblings, stop the
@@ -819,6 +825,25 @@ static inline unlang_t *unlang_group_to_generic(unlang_group_t const *p)
        return UNCONST(unlang_t *, p);
 }
 
+static inline CC_HINT(always_inline) unlang_list_t *unlang_list(unlang_t *unlang)
+{
+       return &unlang_generic_to_group(unlang)->children;
+}
+
+static inline CC_HINT(always_inline) void unlang_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
+{
+       unlang->type = type;
+       unlang->parent = parent;
+       if (parent) unlang->list = unlang_list(parent);
+       unlang_list_entry_init(unlang);
+}
+
+static inline CC_HINT(always_inline) void unlang_group_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
+{
+       unlang_type_init(unlang, parent, type);
+       unlang_list_init(&((unlang_group_t *) unlang)->children);
+}
+
 static inline unlang_tmpl_t *unlang_generic_to_tmpl(unlang_t const *p)
 {
        fr_assert(p->type == UNLANG_TYPE_TMPL);