Mercurial > hg > nginx
diff src/core/ngx_module.c @ 6383:85dea406e18f
Dynamic modules.
The auto/module script is extended to understand ngx_module_link=DYNAMIC.
When set, it links the module as a shared object rather than statically
into nginx binary. The module can later be loaded using the "load_module"
directive.
New auto/module parameter ngx_module_order allows to define module loading
order in complex cases. By default the order is set based on ngx_module_type.
3rd party modules can be compiled dynamically using the --add-dynamic-module
configure option, which will preset ngx_module_link to "DYNAMIC" before
calling the module config script.
Win32 support is rudimentary, and only works when using MinGW gcc (which
is able to handle exports/imports automatically).
In collaboration with Ruslan Ermilov.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 04 Feb 2016 20:25:29 +0300 |
parents | cf5e822cf470 |
children | 5fe617f38222 |
line wrap: on
line diff
--- a/src/core/ngx_module.c Thu Feb 04 18:30:21 2016 +0300 +++ b/src/core/ngx_module.c Thu Feb 04 20:25:29 2016 +0300 @@ -10,7 +10,16 @@ #include <ngx_core.h> -ngx_uint_t ngx_max_module; +#define NGX_MAX_DYNAMIC_MODULES 128 + + +static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle); +static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, + ngx_uint_t index); + + +ngx_uint_t ngx_max_module; +static ngx_uint_t ngx_modules_n; ngx_int_t @@ -20,9 +29,36 @@ ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { - ngx_modules[i]->index = ngx_max_module++; + ngx_modules[i]->index = i; + ngx_modules[i]->name = ngx_module_names[i]; } + ngx_modules_n = i; + ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES; + + return NGX_OK; +} + + +ngx_int_t +ngx_cycle_modules(ngx_cycle_t *cycle) +{ + /* + * create a list of modules to be used for this cycle, + * copy static modules to it + */ + + cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1) + * sizeof(ngx_module_t *)); + if (cycle->modules == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(cycle->modules, ngx_modules, + ngx_modules_n * sizeof(ngx_module_t *)); + + cycle->modules_n = ngx_modules_n; + return NGX_OK; } @@ -47,19 +83,279 @@ ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type) { - ngx_uint_t i, max; + ngx_uint_t i, next, max; + ngx_module_t *module; + next = 0; max = 0; /* count appropriate modules, set up their indices */ for (i = 0; cycle->modules[i]; i++) { - if (cycle->modules[i]->type != type) { + module = cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index != NGX_MODULE_UNSET_INDEX) { + + /* if ctx_index was assigned, preserve it */ + + if (module->ctx_index > max) { + max = module->ctx_index; + } + + if (module->ctx_index == next) { + next++; + } + continue; } - cycle->modules[i]->ctx_index = max++; + /* search for some free index */ + + module->ctx_index = ngx_module_ctx_index(cycle, type, next); + + if (module->ctx_index > max) { + max = module->ctx_index; + } + + next = module->ctx_index + 1; + } + + /* + * make sure the number returned is big enough for previous + * cycle as well, else there will be problems if the number + * will be stored in a global variable (as it's used to be) + * and we'll have to roll back to the previous cycle + */ + + if (cycle->old_cycle && cycle->old_cycle->modules) { + + for (i = 0; cycle->old_cycle->modules[i]; i++) { + module = cycle->old_cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index > max) { + max = module->ctx_index; + } + } + } + + /* prevent loading of additional modules */ + + cycle->modules_used = 1; + + return max + 1; +} + + +ngx_int_t +ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module, + char **order) +{ + void *rv; + ngx_uint_t i, m, before; + ngx_core_module_t *core_module; + + if (cf->cycle->modules_n >= ngx_max_module) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too many modules loaded"); + return NGX_ERROR; + } + + if (module->version != nginx_version) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "module \"%V\" version %ui instead of %ui", + file, module->version, nginx_version); + return NGX_ERROR; + } + + if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "module \"%V\" is not binary compatible", + file); + return NGX_ERROR; + } + + for (m = 0; cf->cycle->modules[m]; m++) { + if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "module \"%s\" is already loaded", + module->name); + return NGX_ERROR; + } + } + + /* + * if the module wasn't previously loaded, assign an index + */ + + if (module->index == NGX_MODULE_UNSET_INDEX) { + module->index = ngx_module_index(cf->cycle); + + if (module->index >= ngx_max_module) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too many modules loaded"); + return NGX_ERROR; + } } - return max; + /* + * put the module into the cycle->modules array + */ + + before = cf->cycle->modules_n; + + if (order) { + for (i = 0; order[i]; i++) { + if (ngx_strcmp(order[i], module->name) == 0) { + i++; + break; + } + } + + for ( /* void */ ; order[i]; i++) { + +#if 0 + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, + "module: %s before %s", + module->name, order[i]); +#endif + + for (m = 0; m < before; m++) { + if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) { + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0, + "module: %s before %s:%i", + module->name, order[i], m); + + before = m; + break; + } + } + } + } + + /* put the module before modules[before] */ + + if (before != cf->cycle->modules_n) { + ngx_memmove(&cf->cycle->modules[before + 1], + &cf->cycle->modules[before], + (cf->cycle->modules_n - before) * sizeof(ngx_module_t *)); + } + + cf->cycle->modules[before] = module; + cf->cycle->modules_n++; + + if (module->type == NGX_CORE_MODULE) { + + /* + * we are smart enough to initialize core modules; + * other modules are expected to be loaded before + * initialization - e.g., http modules must be loaded + * before http{} block + */ + + core_module = module->ctx; + + if (core_module->create_conf) { + rv = core_module->create_conf(cf->cycle); + if (rv == NULL) { + return NGX_ERROR; + } + + cf->cycle->conf_ctx[module->index] = rv; + } + } + + return NGX_OK; } + + +static ngx_uint_t +ngx_module_index(ngx_cycle_t *cycle) +{ + ngx_uint_t i, index; + ngx_module_t *module; + + index = 0; + +again: + + /* find an unused index */ + + for (i = 0; cycle->modules[i]; i++) { + module = cycle->modules[i]; + + if (module->index == index) { + index++; + goto again; + } + } + + /* check previous cycle */ + + if (cycle->old_cycle && cycle->old_cycle->modules) { + + for (i = 0; cycle->old_cycle->modules[i]; i++) { + module = cycle->old_cycle->modules[i]; + + if (module->index == index) { + index++; + goto again; + } + } + } + + return index; +} + + +static ngx_uint_t +ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index) +{ + ngx_uint_t i; + ngx_module_t *module; + +again: + + /* find an unused ctx_index */ + + for (i = 0; cycle->modules[i]; i++) { + module = cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index == index) { + index++; + goto again; + } + } + + /* check previous cycle */ + + if (cycle->old_cycle && cycle->old_cycle->modules) { + + for (i = 0; cycle->old_cycle->modules[i]; i++) { + module = cycle->old_cycle->modules[i]; + + if (module->type != type) { + continue; + } + + if (module->ctx_index == index) { + index++; + goto again; + } + } + } + + return index; +}