From e46168b048380ac1dd614ce7f4f9ea5c7bed2121 Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Tue, 21 Sep 2021 09:06:43 -0400 Subject: [PATCH] add per-thread instantiation for unlang and glue it into the various binaries --- src/bin/unit_test_attribute.c | 2 + src/bin/unit_test_module.c | 2 + src/lib/io/worker.c | 3 + src/lib/unlang/base.c | 2 + src/lib/unlang/base.h | 1 + src/lib/unlang/compile.c | 108 +++++++++++++++++++++++++++++++--- src/lib/unlang/compile.h | 4 ++ src/lib/unlang/unlang_priv.h | 17 ++++++ 8 files changed, 132 insertions(+), 7 deletions(-) diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index 7e793d6cb4..b7d3ab448b 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -3181,6 +3181,8 @@ int main(int argc, char *argv[]) fr_perror("unit_test_attribute"); EXIT_WITH_FAILURE; } + + unlang_thread_instantiate(autofree); if (!xlat_register(NULL, "test", xlat_test, false)) { ERROR("Failed registering xlat"); diff --git a/src/bin/unit_test_module.c b/src/bin/unit_test_module.c index 67f9faa0cc..ee5a4d6d01 100644 --- a/src/bin/unit_test_module.c +++ b/src/bin/unit_test_module.c @@ -728,6 +728,8 @@ int main(int argc, char *argv[]) EXIT_WITH_FAILURE; } + unlang_thread_instantiate(autofree); + /* * Ensure that we load the correct virtual server for the * protocol, if necessary. diff --git a/src/lib/io/worker.c b/src/lib/io/worker.c index 9331395d95..4039a0790c 100644 --- a/src/lib/io/worker.c +++ b/src/lib/io/worker.c @@ -57,6 +57,7 @@ RCSID("$Id$") #include #include #include +#include #include #include #include @@ -1214,6 +1215,8 @@ nomem: worker->name = talloc_strdup(worker, name); /* thread locality */ + unlang_thread_instantiate(worker); + if (config) worker->config = *config; #define CHECK_CONFIG(_x, _min, _max) do { \ diff --git a/src/lib/unlang/base.c b/src/lib/unlang/base.c index 5d3f2ea0d4..2ddf0907db 100644 --- a/src/lib/unlang/base.c +++ b/src/lib/unlang/base.c @@ -86,6 +86,7 @@ int unlang_init_global(void) unlang_interpret_init_global(); /* Register operations for the default keywords */ + unlang_compile_init(); unlang_condition_init(); unlang_foreach_init(); unlang_function_init(); @@ -111,6 +112,7 @@ void unlang_free_global(void) { if (--instance_count > 0) return; + unlang_compile_free(); unlang_foreach_free(); unlang_subrequest_op_free(); xlat_free(); diff --git a/src/lib/unlang/base.h b/src/lib/unlang/base.h index 968c3e5d07..9344383a32 100644 --- a/src/lib/unlang/base.h +++ b/src/lib/unlang/base.h @@ -40,6 +40,7 @@ int unlang_init_global(void); void unlang_free_global(void); +int unlang_thread_instantiate(TALLOC_CTX *ctx) CC_HINT(nonnull); #ifdef __cplusplus } diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index 77c7824a91..3ea331accb 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -45,6 +45,17 @@ RCSID("$Id$") #define UNLANG_IGNORE ((unlang_t *) -1) +static unsigned int unlang_number = 0; + +/* + * For simplicity, this is just array[unlang_number]. Once we + * call unlang_thread_instantiate(), the "unlang_number" above MUST + * NOT change. + */ +static _Thread_local unlang_thread_t *unlang_thread_array; + +static fr_rb_tree_t *unlang_instruction_tree = NULL; + /* Here's where we recognize all of our keywords: first the rcodes, then the * actions */ fr_table_num_sorted_t const mod_rcode_table[] = { @@ -3727,7 +3738,7 @@ static int unlang_pair_keywords_len = NUM_ELEMENTS(unlang_pair_keywords); /* - * Compile one entry of a module call. + * Compile one unlang instruction */ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci) { @@ -3740,13 +3751,22 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO module_method_t method; bool policy; unlang_op_compile_t compile; + unlang_t *c; if (cf_item_is_section(ci)) { cs = cf_item_to_section(ci); name = cf_section_name1(cs); compile = (unlang_op_compile_t) fr_table_value_by_str(unlang_section_keywords, name, NULL); - if (compile) return compile(parent, unlang_ctx, ci); + if (compile) { + c = compile(parent, unlang_ctx, ci); + allocate_number: + if (!c) return NULL; + if (c == UNLANG_IGNORE) return UNLANG_IGNORE; + + c->number = unlang_number++; + return c; + } /* * Forbid pair keywords as section names, e.g. "break { ... }" @@ -3785,11 +3805,15 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO */ if (((name[0] == '%') && ((name[1] == '{') || (name[1] == '('))) || (cf_pair_attr_quote(cp) == T_BACK_QUOTED_STRING)) { - return compile_tmpl(parent, unlang_ctx, cp); + c = compile_tmpl(parent, unlang_ctx, cp); + goto allocate_number; } compile = (unlang_op_compile_t)fr_table_value_by_str(unlang_pair_keywords, name, NULL); /* Cast for -Wpedantic */ - if (compile) return compile(parent, unlang_ctx, ci); + if (compile) { + c = compile(parent, unlang_ctx, ci); + goto allocate_number; + } /* * Forbid section keywords as pair names, e.g. bare "update" @@ -3865,7 +3889,10 @@ check_for_module: * named redundant / load-balance subsection defined in * "instantiate". */ - if (subcs) return compile_function(parent, unlang_ctx, ci, subcs, component, policy); + if (subcs) { + c = compile_function(parent, unlang_ctx, ci, subcs, component, policy); + goto allocate_number; + } /* * Not a function. It must be a real module. @@ -3891,7 +3918,8 @@ check_for_module: &unlang_ctx2.section_name1, &unlang_ctx2.section_name2, realname); if (inst) { - return compile_module(parent, &unlang_ctx2, ci, inst, method, realname); + c = compile_module(parent, &unlang_ctx2, ci, inst, method, realname); + goto allocate_number; } /* @@ -3934,7 +3962,8 @@ int unlang_compile(CONF_SECTION *cs, rlm_components_t component, tmpl_rules_t co .type = UNLANG_TYPE_GROUP, .len = sizeof(unlang_group_t), .type_name = "unlang_group_t", - }; + }; + /* * Don't compile it twice, and don't print out debug * messages twice. @@ -4000,3 +4029,68 @@ bool unlang_compile_is_keyword(const char *name) return (fr_table_value_by_str(unlang_pair_keywords, name, NULL) != NULL); } + +static int8_t instruction_cmp(void const *one, void const *two) +{ + unlang_t const *a = one; + unlang_t const *b = two; + + return CMP(a->number, b->number); +} + + +void unlang_compile_init() +{ + unlang_instruction_tree = fr_rb_talloc_alloc(NULL, unlang_t, instruction_cmp, NULL); +} + +void unlang_compile_free() +{ + TALLOC_FREE(unlang_instruction_tree); +} + + +/** Create thread-specific data structures for unlang + * + */ +int unlang_thread_instantiate(TALLOC_CTX *ctx) +{ + fr_rb_iter_inorder_t iter; + unlang_t *instruction; + + if (unlang_thread_array) { + fr_strerror_const("already initialized"); + return -1; + } + + MEM(unlang_thread_array = talloc_zero_array(ctx, unlang_thread_t, unlang_number + 1)); +// talloc_set_destructor(unlang_thread_array, _unlang_thread_array_free); + + /* + * Instantiate each instruction with thread-specific data. + */ + for (instruction = fr_rb_iter_init_inorder(&iter, unlang_instruction_tree); + instruction; + instruction = fr_rb_iter_next_inorder(&iter)) { + unlang_op_t *op; + + unlang_thread_array[instruction->number].instruction = instruction; + + op = &unlang_ops[instruction->type]; + if (!op->thread_instantiate) continue; + + /* + * Allocate any thread-specific instance data. + */ + if (op->thread_inst_size) { + MEM(unlang_thread_array[instruction->number].thread_inst = talloc_zero_array(unlang_thread_array, uint8_t, op->thread_inst_size)); + talloc_set_name_const(unlang_thread_array[instruction->number].thread_inst, op->thread_inst_type); + } + + if (op->thread_instantiate(instruction, unlang_thread_array[instruction->number].thread_inst) < 0) { + return -1; + } + } + + return 0; +} diff --git a/src/lib/unlang/compile.h b/src/lib/unlang/compile.h index 1e7b579ee1..e584f90311 100644 --- a/src/lib/unlang/compile.h +++ b/src/lib/unlang/compile.h @@ -38,6 +38,10 @@ typedef struct { fr_retry_config_t retry; } unlang_actions_t; +void unlang_compile_init(void); + +void unlang_compile_free(void); + int unlang_compile(CONF_SECTION *cs, rlm_components_t component, tmpl_rules_t const *rules, void **instruction); bool unlang_compile_is_keyword(const char *name); diff --git a/src/lib/unlang/unlang_priv.h b/src/lib/unlang/unlang_priv.h index 00763f67e9..85b62d86d7 100644 --- a/src/lib/unlang/unlang_priv.h +++ b/src/lib/unlang/unlang_priv.h @@ -122,6 +122,7 @@ struct unlang_s { char const *debug_name; //!< Printed in log messages when the node is executed. unlang_type_t type; //!< The specialisation of this node. bool closed; //!< whether or not this section is closed to new statements + unsigned int number; //!< unique node number unlang_actions_t actions; //!< Priorities, etc. for the various return codes. }; @@ -192,6 +193,8 @@ typedef void (*unlang_signal_t)(request_t *request, */ typedef void (*unlang_dump_t)(request_t *request, unlang_stack_frame_t *frame); +typedef int (*unlang_thread_instantiate_t)(unlang_t const *instruction, void *thread_inst); + /** An unlang operation * * These are like the opcodes in other interpreters. Each operation, when executed @@ -206,6 +209,11 @@ typedef struct { unlang_dump_t dump; //!< Dump additional information about the frame state. + unlang_thread_instantiate_t thread_instantiate; //!< per-thread instantiation function + size_t thread_inst_size; + char const *thread_inst_type; + + bool debug_braces; //!< Whether the operation needs to print braces ///< in debug mode. @@ -218,6 +226,14 @@ typedef struct { size_t frame_state_pool_size; //!< The total size of the pool to alloc. } unlang_op_t; +typedef struct { + unlang_t const *instruction; //!< instruction which we're executing + void *thread_inst; //!< thread-specific instance data + /* + * And various other stats + */ +} unlang_thread_t; + typedef struct { request_t *request; int depth; //!< of this retry structure @@ -504,6 +520,7 @@ int unlang_interpret_push(request_t *request, unlang_t const *instruction, int unlang_op_init(void); void unlang_op_free(void); + /** @} */ /** @name io shims -- 2.47.2