From 0991eb01efb69532d0f5248c4a13894605284614 Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Sun, 27 Jul 2025 11:06:38 -0400 Subject: [PATCH] move unlang_t to use dlists --- src/lib/unlang/call.c | 4 +++- src/lib/unlang/caller.c | 4 ++-- src/lib/unlang/catch.c | 35 +++++++++++++----------------- src/lib/unlang/compile.c | 41 ++++++++++------------------------- src/lib/unlang/condition.c | 19 ++++++++++++---- src/lib/unlang/edit.c | 2 ++ src/lib/unlang/interpret.c | 8 +++---- src/lib/unlang/load_balance.c | 30 ++++++++++++++----------- src/lib/unlang/map.c | 4 ++-- src/lib/unlang/module.c | 1 + src/lib/unlang/parallel.c | 25 ++++++++++++--------- src/lib/unlang/subrequest.c | 6 +++-- src/lib/unlang/switch.c | 6 ++--- src/lib/unlang/tmpl.c | 1 + src/lib/unlang/unlang_priv.h | 39 +++++++++++++++++++++++++++------ 15 files changed, 126 insertions(+), 99 deletions(-) diff --git a/src/lib/unlang/call.c b/src/lib/unlang/call.c index f6267ea259..320948351b 100644 --- a/src/lib/unlang/call.c +++ b/src/lib/unlang/call.c @@ -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 */ diff --git a/src/lib/unlang/caller.c b/src/lib/unlang/caller.c index 30e187d22c..b6a38d7b55 100644 --- a/src/lib/unlang/caller.c +++ b/src/lib/unlang/caller.c @@ -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; } diff --git a/src/lib/unlang/catch.c b/src/lib/unlang/catch.c index 70ef78fb7d..f8fdd465ec 100644 --- a/src/lib/unlang/catch.c +++ b/src/lib/unlang/catch.c @@ -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, "")); 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, "")); + return frame_set_next(frame, NULL); } static int catch_argv(CONF_SECTION *cs, unlang_catch_t *ca, char const *name) diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index e9772e7e52..fb70c8231b 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -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); } } diff --git a/src/lib/unlang/condition.c b/src/lib/unlang/condition.c index bccda50f6b..6219be2e11 100644 --- a/src/lib/unlang/condition.c +++ b/src/lib/unlang/condition.c @@ -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. */ diff --git a/src/lib/unlang/edit.c b/src/lib/unlang/edit.c index 34a6c47a9b..38fd839326 100644 --- a/src/lib/unlang/edit.c +++ b/src/lib/unlang/edit.c @@ -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); /* diff --git a/src/lib/unlang/interpret.c b/src/lib/unlang/interpret.c index f4efc435e6..ea9d112b7a 100644 --- a/src/lib/unlang/interpret.c +++ b/src/lib/unlang/interpret.c @@ -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; } diff --git a/src/lib/unlang/load_balance.c b/src/lib/unlang/load_balance.c index 55891ee3db..fa4fd1acfe 100644 --- a/src/lib/unlang/load_balance.c +++ b/src/lib/unlang/load_balance.c @@ -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); diff --git a/src/lib/unlang/map.c b/src/lib/unlang/map.c index 72adf8e442..cc6bc1fef2 100644 --- a/src/lib/unlang/map.c +++ b/src/lib/unlang/map.c @@ -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); diff --git a/src/lib/unlang/module.c b/src/lib/unlang/module.c index 46fd9bdbe0..22e706f2bd 100644 --- a/src/lib/unlang/module.c +++ b/src/lib/unlang/module.c @@ -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 diff --git a/src/lib/unlang/parallel.c b/src/lib/unlang/parallel.c index 4b50b54271..05b0d28fec 100644 --- a/src/lib/unlang/parallel.c +++ b/src/lib/unlang/parallel.c @@ -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) { diff --git a/src/lib/unlang/subrequest.c b/src/lib/unlang/subrequest.c index 6e5fb5b11c..154e10d813 100644 --- a/src/lib/unlang/subrequest.c +++ b/src/lib/unlang/subrequest.c @@ -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 { ... } * diff --git a/src/lib/unlang/switch.c b/src/lib/unlang/switch.c index 2673bafaf3..ca5f0cb846 100644 --- a/src/lib/unlang/switch.c +++ b/src/lib/unlang/switch.c @@ -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; diff --git a/src/lib/unlang/tmpl.c b/src/lib/unlang/tmpl.c index 02a24f8d8e..c1bf1062c1 100644 --- a/src/lib/unlang/tmpl.c +++ b/src/lib/unlang/tmpl.c @@ -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 diff --git a/src/lib/unlang/unlang_priv.h b/src/lib/unlang/unlang_priv.h index 95bb2105a8..35840bf7bc 100644 --- a/src/lib/unlang/unlang_priv.h +++ b/src/lib/unlang/unlang_priv.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -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); -- 2.47.3