From: Arran Cudbard-Bell Date: Thu, 24 Nov 2016 21:53:51 +0000 (-0500) Subject: Add per module/thread instantiation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a85a2dff6d0cd86dba03b5316cf42a56f1f14fa1;p=thirdparty%2Ffreeradius-server.git Add per module/thread instantiation --- diff --git a/src/include/modpriv.h b/src/include/modpriv.h index 2037711d79c..30088840b57 100644 --- a/src/include/modpriv.h +++ b/src/include/modpriv.h @@ -39,7 +39,7 @@ extern "C" { * instance names (may NOT be the module names!), and the per-instance * data structures. */ -typedef struct module_instance { +typedef struct { char const *name; //!< Instance name e.g. user_database. rad_module_t const *module; //!< Module this is an instance of. @@ -60,6 +60,16 @@ typedef struct module_instance { //!< has been set to true. } module_instance_t; +/** Per thread per instance data + * + * Stores module and thread specific data. + */ +typedef struct { + module_instance_t *inst; //!< Non-thread local instance of this + + void *data; //!< Thread specific instance data. +} module_thread_instance_t; + module_instance_t *module_find_with_method(rlm_components_t *method, CONF_SECTION *modules, char const *asked_name); module_instance_t *module_find(CONF_SECTION *modules, char const *asked_name); diff --git a/src/include/modules.h b/src/include/modules.h index 52fded63a2f..a02a114149e 100644 --- a/src/include/modules.h +++ b/src/include/modules.h @@ -124,6 +124,20 @@ typedef int (*module_instantiate_t)(CONF_SECTION *mod_cs, void *instance); */ typedef int (*module_thread_t)(CONF_SECTION *mod_cs, void *instance, void *thread); +/** Module thread destruction callback + * + * Destroy a module/thread instance. + * + * @param[in] instance data, specific to an instantiated module. + * Pre-allocated, and populated during the + * bootstrap and instantiate calls. + * @param[in] thread data specific to this module instance. + * @return + * - 0 on success. + * - -1 if instantiation failed. + */ +typedef int (*module_thread_detach_t)(void *instance, void *thread); + /** Struct exported by a rlm_* module * * Determines the capabilities of the module, and maps internal functions @@ -136,8 +150,11 @@ typedef struct rad_module_t { module_instantiate_t bootstrap; //!< Callback to register dynamic attrs, xlats, etc. module_instantiate_t instantiate; //!< Callback to configure a new module instance. - module_thread_t thread; //!< Callback to configure a module's instance for + + module_thread_t thread_instantiate; //!< Callback to configure a module's instance for //!< a new worker thread. + module_thread_detach_t thread_detach; //!< Destroy thread specific data. + size_t thread_inst_size; //!< Size of data to allocate to the thread instance. module_method_t methods[MOD_COUNT]; //!< Pointers to the various section callbacks. } rad_module_t; @@ -162,8 +179,10 @@ exfile_t *module_exfile_init(TALLOC_CTX *ctx, /* * Create free and destroy module instances */ -int modules_bootstrap(CONF_SECTION *root) CC_HINT(nonnull); +void *module_thread_instance_find(void *inst); +int modules_thread_instantiate(CONF_SECTION *root) CC_HINT(nonnull); int modules_instantiate(CONF_SECTION *root) CC_HINT(nonnull); +int modules_bootstrap(CONF_SECTION *root) CC_HINT(nonnull); int modules_free(void); int module_instance_read_only(TALLOC_CTX *ctx, char const *name); diff --git a/src/main/modules.c b/src/main/modules.c index 7aff8e703e7..cea9922e3a4 100644 --- a/src/main/modules.c +++ b/src/main/modules.c @@ -32,6 +32,8 @@ RCSID("$Id$") #include #include +fr_thread_local_setup(rbtree_t *, module_thread_inst_tree); + static TALLOC_CTX *instance_ctx = NULL; /* @@ -381,6 +383,20 @@ module_instance_t *module_find(CONF_SECTION *modules, char const *asked_name) return talloc_get_type_abort(inst, module_instance_t); } +/** Free all modules loaded by the server + * + * @return 0. + */ +int modules_free(void) +{ + /* + * Free instances first, then dynamic libraries. + */ + TALLOC_FREE(instance_ctx); + + return 0; +} + /** Find an existing module instance and verify it implements the specified method * * Extracts the method from the module name where the format is @verbatim . @endverbatim @@ -443,16 +459,137 @@ module_instance_t *module_find_with_method(rlm_components_t *method, CONF_SECTIO return inst; } -/** Free all modules loaded by the server +/** Retrieve module/thread specific instance data for a module * - * @return 0. + * @param[in] instance to find thread specific data for. + * @return + * - Thread specific instance data on success. + * - NULL if module has no thread instance data. */ -int modules_free(void) +void *module_thread_instance_find(void *instance) { - /* - * Free instances first, then dynamic libraries. - */ - TALLOC_FREE(instance_ctx); + module_instance_t *inst = instance; + rbtree_t *tree = fr_thread_local_get(module_thread_inst_tree); + module_thread_instance_t find, *found; + + if (!inst->module->thread_instantiate || !inst->module->thread_inst_size) return NULL; + + memset(&find, 0, sizeof(find)); + find.inst = inst; + + found = rbtree_finddata(tree, &find); + if (!found) return NULL; + + return found->data; +} + +/** Destructor for module_thread_instance_t + * + */ +static int _module_thread_instance_free(void *thread_inst_data) +{ + module_thread_instance_t *thread_inst = talloc_parent(thread_inst_data); + + if (thread_inst->inst->module->thread_detach) { + (void) thread_inst->inst->module->thread_detach(thread_inst->inst, thread_inst->data); + } + + return 0; +} + +/** Frees the thread local instance free and any thread local instance data + * + * @param[in] to_free Thread specific module instance tree to free. + */ +static void _module_thread_inst_tree_free(void *to_free) +{ + rbtree_t *thread_inst_tree = talloc_get_type_abort(to_free, rbtree_t); + rbtree_free(thread_inst_tree); +} + +/** Compare two thread instances based on inst pointer + * + * @param[in] a First thread specific module instance. + * @param[in] b Second thread specific module instance. + * @return + * - +1 if a > b. + * - -1 if a < b. + * - 0 if a == b. + */ +static int _module_thread_inst_tree_cmp(void const *a, void const *b) +{ + module_thread_instance_t const *my_a = a, *my_b = b; + + if (my_a->inst > my_b->inst) return +1; + if (my_a->inst < my_b->inst) return -1; + + return 0; +} + +/** Setup thread specific instance data for a module + * + * @param[in] instance of module to perform thread instantiation for. + * @param[in] ctx modules section, containing instance data. + * @return + * - 0 on success. + * - -1 on failure. + */ +static int _module_thread_instantiate(void *instance, UNUSED void *ctx) +{ + module_instance_t *inst = talloc_get_type_abort(instance, module_instance_t); + module_thread_instance_t *thread_inst; + rbtree_t *thread_inst_tree = talloc_get_type_abort(ctx, rbtree_t); + int ret; + + if (!inst->module->thread_instantiate) return 0; + + MEM(thread_inst = talloc_zero(NULL, module_thread_instance_t)); + thread_inst->inst = inst; + + if (inst->module->thread_inst_size) { + MEM(thread_inst->data = talloc_zero_array(thread_inst, uint8_t, inst->module->thread_inst_size)); + talloc_set_name(thread_inst->data, "%s", inst->name); + talloc_set_destructor(thread_inst->data, _module_thread_instance_free); + rbtree_insert(thread_inst_tree, thread_inst); + } + + ret = inst->module->thread_instantiate(inst->cs, inst, thread_inst->data); + if (ret < 0) { + ERROR("Thread instantiation failed for module \"%s\"", inst->name); + return -1; + } + + return 0; +} + +/** Creates per-thread instance data for modules which need it + * + * Must be called by any new threads before attempting to execute unlang sections. + * + * @param[in] root Configuration root. + * @return + * - 0 on success. + * - -1 on failure. + */ +int modules_thread_instantiate(CONF_SECTION *root) +{ + CONF_SECTION *modules; + rbtree_t *thread_inst_tree; + + modules = cf_section_sub_find(root, "modules"); + if (!modules) return 0; + + thread_inst_tree = fr_thread_local_init(module_thread_inst_tree, _module_thread_inst_tree_free); + if (!thread_inst_tree) { + MEM(thread_inst_tree = rbtree_create(NULL, _module_thread_inst_tree_cmp, rbtree_node_talloc_free, 0)); + fr_thread_local_set(module_thread_inst_tree, thread_inst_tree); + } + + if (cf_data_walk(modules, CF_DATA_TYPE_MODULE_INSTANCE, _module_thread_instantiate, thread_inst_tree) < 0) { + _module_thread_inst_tree_free(thread_inst_tree); /* make re-entrant */ + fr_thread_local_set(module_thread_inst_tree, NULL); + return -1; + } return 0; } diff --git a/src/main/threads.c b/src/main/threads.c index d6771d09fad..2b85c20bab2 100644 --- a/src/main/threads.c +++ b/src/main/threads.c @@ -28,6 +28,7 @@ USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ #include #include #include +#include #ifdef HAVE_SYS_WAIT_H # include @@ -471,6 +472,14 @@ static void *thread_handler(void *arg) goto done; } + /* + * Perform thread specific module instantiation + */ + if (modules_thread_instantiate(main_config.config) < 0) { + ERROR("Thread instantiation failed"); + goto done; + } + thread->status = THREAD_ACTIVE; /* diff --git a/src/main/unit_test_module.c b/src/main/unit_test_module.c index 0b1a872cbc0..6f83784b3a2 100644 --- a/src/main/unit_test_module.c +++ b/src/main/unit_test_module.c @@ -812,10 +812,15 @@ int main(int argc, char *argv[]) if (modules_bootstrap(main_config.config) < 0) goto exit_failure; /* - * Load the modules + * Instantiate the modules */ if (modules_instantiate(main_config.config) < 0) goto exit_failure; + /* + * Perform any thread specific instantiation + */ + if (modules_thread_instantiate(main_config.config) < 0) goto exit_failure; + /* * And then load the virtual servers. */ diff --git a/src/modules/rlm_test/rlm_test.c b/src/modules/rlm_test/rlm_test.c index 43bf7f7126e..6635d16e075 100644 --- a/src/modules/rlm_test/rlm_test.c +++ b/src/modules/rlm_test/rlm_test.c @@ -98,6 +98,10 @@ typedef struct rlm_test_t { _timeval_t *timeval_m; } rlm_test_t; +typedef struct { + pthread_t value; +} rlm_test_thread_t; + /* * A mapping of configuration file names to internal variables. */ @@ -173,6 +177,27 @@ static int rlm_test_cmp(UNUSED void *instance, REQUEST *request, UNUSED VALUE_PA return 1; } +static int mod_thread_instantiate(UNUSED CONF_SECTION *conf, UNUSED void *instance, void *thread) +{ + rlm_test_thread_t *t = thread; + + t->value = pthread_self(); + INFO("Performing instantiation for thread %p", t->value); + + return 0; +} + +static int mod_thread_detach(UNUSED void *instance, void *thread) +{ + rlm_test_thread_t *t = thread; + + INFO("Performing detach for thread %p", t->value); + + if (!rad_cond_assert(t->value == pthread_self())) return RLM_MODULE_FAIL; + + return 0; +} + /* * Do any per-module initialization that is separate to each * configured instance of the module. e.g. set up connections @@ -215,6 +240,8 @@ static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance) */ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED void *thread, REQUEST *request) { + rlm_test_thread_t *t = thread; + RINFO("RINFO message"); RDEBUG("RDEBUG message"); RDEBUG2("RDEBUG2 message"); @@ -240,6 +267,8 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REXDENT(); REDEBUG4("RDEBUG4 error message"); + if (!rad_cond_assert(t->value == pthread_self())) return RLM_MODULE_FAIL; + return RLM_MODULE_OK; } @@ -248,6 +277,10 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, UNUSED void *thread, UNUSED REQUEST *request) { + rlm_test_thread_t *t = thread; + + if (!rad_cond_assert(t->value == pthread_self())) return RLM_MODULE_FAIL; + return RLM_MODULE_OK; } @@ -257,6 +290,10 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, UNUS */ static rlm_rcode_t CC_HINT(nonnull) mod_preacct(UNUSED void *instance, UNUSED void *thread, UNUSED REQUEST *request) { + rlm_test_thread_t *t = thread; + + if (!rad_cond_assert(t->value == pthread_self())) return RLM_MODULE_FAIL; + return RLM_MODULE_OK; } @@ -265,6 +302,10 @@ static rlm_rcode_t CC_HINT(nonnull) mod_preacct(UNUSED void *instance, UNUSED vo */ static rlm_rcode_t CC_HINT(nonnull) mod_accounting(UNUSED void *instance, UNUSED void *thread, UNUSED REQUEST *request) { + rlm_test_thread_t *t = thread; + + if (!rad_cond_assert(t->value == pthread_self())) return RLM_MODULE_FAIL; + return RLM_MODULE_OK; } @@ -280,7 +321,11 @@ static rlm_rcode_t CC_HINT(nonnull) mod_accounting(UNUSED void *instance, UNUSED */ static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(UNUSED void *instance, UNUSED void *thread, REQUEST *request) { - request->simul_count=0; + rlm_test_thread_t *t = thread; + + request->simul_count = 0; + + if (!rad_cond_assert(t->value == pthread_self())) return RLM_MODULE_FAIL; return RLM_MODULE_OK; } @@ -308,13 +353,16 @@ static int mod_detach(UNUSED void *instance) */ extern rad_module_t rlm_test; rad_module_t rlm_test = { - .magic = RLM_MODULE_INIT, - .name = "test", - .type = RLM_TYPE_THREAD_SAFE, - .inst_size = sizeof(rlm_test_t), - .config = module_config, - .instantiate = mod_instantiate, - .detach = mod_detach, + .magic = RLM_MODULE_INIT, + .name = "test", + .type = RLM_TYPE_THREAD_SAFE, + .inst_size = sizeof(rlm_test_t), + .thread_inst_size = sizeof(rlm_test_thread_t), + .config = module_config, + .instantiate = mod_instantiate, + .thread_instantiate = mod_thread_instantiate, + .thread_detach = mod_thread_detach, + .detach = mod_detach, .methods = { [MOD_AUTHENTICATE] = mod_authenticate, [MOD_AUTHORIZE] = mod_authorize, diff --git a/src/util/worker.c b/src/util/worker.c index 39682429d45..7e9eab517a9 100644 --- a/src/util/worker.c +++ b/src/util/worker.c @@ -511,6 +511,17 @@ void *fr_worker(UNUSED void *arg) return NULL; } +#if 0 + /* + * Perform thread specific module instantiation + */ + if (modules_thread_instantiate(main_config.config) < 0) { + ERROR("Thread instantiation failed"); + talloc_free(ctx); + return NULL; + } +#endif + while (true) { bool wait_for_event; int num_events;