Mercurial > hg > nginx
comparison 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 |
comparison
equal
deleted
inserted
replaced
6382:392959224560 | 6383:85dea406e18f |
---|---|
8 | 8 |
9 #include <ngx_config.h> | 9 #include <ngx_config.h> |
10 #include <ngx_core.h> | 10 #include <ngx_core.h> |
11 | 11 |
12 | 12 |
13 ngx_uint_t ngx_max_module; | 13 #define NGX_MAX_DYNAMIC_MODULES 128 |
14 | |
15 | |
16 static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle); | |
17 static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, | |
18 ngx_uint_t index); | |
19 | |
20 | |
21 ngx_uint_t ngx_max_module; | |
22 static ngx_uint_t ngx_modules_n; | |
14 | 23 |
15 | 24 |
16 ngx_int_t | 25 ngx_int_t |
17 ngx_preinit_modules() | 26 ngx_preinit_modules() |
18 { | 27 { |
19 ngx_uint_t i; | 28 ngx_uint_t i; |
20 | 29 |
21 ngx_max_module = 0; | 30 ngx_max_module = 0; |
22 for (i = 0; ngx_modules[i]; i++) { | 31 for (i = 0; ngx_modules[i]; i++) { |
23 ngx_modules[i]->index = ngx_max_module++; | 32 ngx_modules[i]->index = i; |
24 } | 33 ngx_modules[i]->name = ngx_module_names[i]; |
34 } | |
35 | |
36 ngx_modules_n = i; | |
37 ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES; | |
38 | |
39 return NGX_OK; | |
40 } | |
41 | |
42 | |
43 ngx_int_t | |
44 ngx_cycle_modules(ngx_cycle_t *cycle) | |
45 { | |
46 /* | |
47 * create a list of modules to be used for this cycle, | |
48 * copy static modules to it | |
49 */ | |
50 | |
51 cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1) | |
52 * sizeof(ngx_module_t *)); | |
53 if (cycle->modules == NULL) { | |
54 return NGX_ERROR; | |
55 } | |
56 | |
57 ngx_memcpy(cycle->modules, ngx_modules, | |
58 ngx_modules_n * sizeof(ngx_module_t *)); | |
59 | |
60 cycle->modules_n = ngx_modules_n; | |
25 | 61 |
26 return NGX_OK; | 62 return NGX_OK; |
27 } | 63 } |
28 | 64 |
29 | 65 |
45 | 81 |
46 | 82 |
47 ngx_int_t | 83 ngx_int_t |
48 ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type) | 84 ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type) |
49 { | 85 { |
50 ngx_uint_t i, max; | 86 ngx_uint_t i, next, max; |
51 | 87 ngx_module_t *module; |
88 | |
89 next = 0; | |
52 max = 0; | 90 max = 0; |
53 | 91 |
54 /* count appropriate modules, set up their indices */ | 92 /* count appropriate modules, set up their indices */ |
55 | 93 |
56 for (i = 0; cycle->modules[i]; i++) { | 94 for (i = 0; cycle->modules[i]; i++) { |
57 if (cycle->modules[i]->type != type) { | 95 module = cycle->modules[i]; |
96 | |
97 if (module->type != type) { | |
58 continue; | 98 continue; |
59 } | 99 } |
60 | 100 |
61 cycle->modules[i]->ctx_index = max++; | 101 if (module->ctx_index != NGX_MODULE_UNSET_INDEX) { |
62 } | 102 |
63 | 103 /* if ctx_index was assigned, preserve it */ |
64 return max; | 104 |
65 } | 105 if (module->ctx_index > max) { |
106 max = module->ctx_index; | |
107 } | |
108 | |
109 if (module->ctx_index == next) { | |
110 next++; | |
111 } | |
112 | |
113 continue; | |
114 } | |
115 | |
116 /* search for some free index */ | |
117 | |
118 module->ctx_index = ngx_module_ctx_index(cycle, type, next); | |
119 | |
120 if (module->ctx_index > max) { | |
121 max = module->ctx_index; | |
122 } | |
123 | |
124 next = module->ctx_index + 1; | |
125 } | |
126 | |
127 /* | |
128 * make sure the number returned is big enough for previous | |
129 * cycle as well, else there will be problems if the number | |
130 * will be stored in a global variable (as it's used to be) | |
131 * and we'll have to roll back to the previous cycle | |
132 */ | |
133 | |
134 if (cycle->old_cycle && cycle->old_cycle->modules) { | |
135 | |
136 for (i = 0; cycle->old_cycle->modules[i]; i++) { | |
137 module = cycle->old_cycle->modules[i]; | |
138 | |
139 if (module->type != type) { | |
140 continue; | |
141 } | |
142 | |
143 if (module->ctx_index > max) { | |
144 max = module->ctx_index; | |
145 } | |
146 } | |
147 } | |
148 | |
149 /* prevent loading of additional modules */ | |
150 | |
151 cycle->modules_used = 1; | |
152 | |
153 return max + 1; | |
154 } | |
155 | |
156 | |
157 ngx_int_t | |
158 ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module, | |
159 char **order) | |
160 { | |
161 void *rv; | |
162 ngx_uint_t i, m, before; | |
163 ngx_core_module_t *core_module; | |
164 | |
165 if (cf->cycle->modules_n >= ngx_max_module) { | |
166 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
167 "too many modules loaded"); | |
168 return NGX_ERROR; | |
169 } | |
170 | |
171 if (module->version != nginx_version) { | |
172 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
173 "module \"%V\" version %ui instead of %ui", | |
174 file, module->version, nginx_version); | |
175 return NGX_ERROR; | |
176 } | |
177 | |
178 if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) { | |
179 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
180 "module \"%V\" is not binary compatible", | |
181 file); | |
182 return NGX_ERROR; | |
183 } | |
184 | |
185 for (m = 0; cf->cycle->modules[m]; m++) { | |
186 if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) { | |
187 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
188 "module \"%s\" is already loaded", | |
189 module->name); | |
190 return NGX_ERROR; | |
191 } | |
192 } | |
193 | |
194 /* | |
195 * if the module wasn't previously loaded, assign an index | |
196 */ | |
197 | |
198 if (module->index == NGX_MODULE_UNSET_INDEX) { | |
199 module->index = ngx_module_index(cf->cycle); | |
200 | |
201 if (module->index >= ngx_max_module) { | |
202 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
203 "too many modules loaded"); | |
204 return NGX_ERROR; | |
205 } | |
206 } | |
207 | |
208 /* | |
209 * put the module into the cycle->modules array | |
210 */ | |
211 | |
212 before = cf->cycle->modules_n; | |
213 | |
214 if (order) { | |
215 for (i = 0; order[i]; i++) { | |
216 if (ngx_strcmp(order[i], module->name) == 0) { | |
217 i++; | |
218 break; | |
219 } | |
220 } | |
221 | |
222 for ( /* void */ ; order[i]; i++) { | |
223 | |
224 #if 0 | |
225 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, | |
226 "module: %s before %s", | |
227 module->name, order[i]); | |
228 #endif | |
229 | |
230 for (m = 0; m < before; m++) { | |
231 if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) { | |
232 | |
233 ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0, | |
234 "module: %s before %s:%i", | |
235 module->name, order[i], m); | |
236 | |
237 before = m; | |
238 break; | |
239 } | |
240 } | |
241 } | |
242 } | |
243 | |
244 /* put the module before modules[before] */ | |
245 | |
246 if (before != cf->cycle->modules_n) { | |
247 ngx_memmove(&cf->cycle->modules[before + 1], | |
248 &cf->cycle->modules[before], | |
249 (cf->cycle->modules_n - before) * sizeof(ngx_module_t *)); | |
250 } | |
251 | |
252 cf->cycle->modules[before] = module; | |
253 cf->cycle->modules_n++; | |
254 | |
255 if (module->type == NGX_CORE_MODULE) { | |
256 | |
257 /* | |
258 * we are smart enough to initialize core modules; | |
259 * other modules are expected to be loaded before | |
260 * initialization - e.g., http modules must be loaded | |
261 * before http{} block | |
262 */ | |
263 | |
264 core_module = module->ctx; | |
265 | |
266 if (core_module->create_conf) { | |
267 rv = core_module->create_conf(cf->cycle); | |
268 if (rv == NULL) { | |
269 return NGX_ERROR; | |
270 } | |
271 | |
272 cf->cycle->conf_ctx[module->index] = rv; | |
273 } | |
274 } | |
275 | |
276 return NGX_OK; | |
277 } | |
278 | |
279 | |
280 static ngx_uint_t | |
281 ngx_module_index(ngx_cycle_t *cycle) | |
282 { | |
283 ngx_uint_t i, index; | |
284 ngx_module_t *module; | |
285 | |
286 index = 0; | |
287 | |
288 again: | |
289 | |
290 /* find an unused index */ | |
291 | |
292 for (i = 0; cycle->modules[i]; i++) { | |
293 module = cycle->modules[i]; | |
294 | |
295 if (module->index == index) { | |
296 index++; | |
297 goto again; | |
298 } | |
299 } | |
300 | |
301 /* check previous cycle */ | |
302 | |
303 if (cycle->old_cycle && cycle->old_cycle->modules) { | |
304 | |
305 for (i = 0; cycle->old_cycle->modules[i]; i++) { | |
306 module = cycle->old_cycle->modules[i]; | |
307 | |
308 if (module->index == index) { | |
309 index++; | |
310 goto again; | |
311 } | |
312 } | |
313 } | |
314 | |
315 return index; | |
316 } | |
317 | |
318 | |
319 static ngx_uint_t | |
320 ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index) | |
321 { | |
322 ngx_uint_t i; | |
323 ngx_module_t *module; | |
324 | |
325 again: | |
326 | |
327 /* find an unused ctx_index */ | |
328 | |
329 for (i = 0; cycle->modules[i]; i++) { | |
330 module = cycle->modules[i]; | |
331 | |
332 if (module->type != type) { | |
333 continue; | |
334 } | |
335 | |
336 if (module->ctx_index == index) { | |
337 index++; | |
338 goto again; | |
339 } | |
340 } | |
341 | |
342 /* check previous cycle */ | |
343 | |
344 if (cycle->old_cycle && cycle->old_cycle->modules) { | |
345 | |
346 for (i = 0; cycle->old_cycle->modules[i]; i++) { | |
347 module = cycle->old_cycle->modules[i]; | |
348 | |
349 if (module->type != type) { | |
350 continue; | |
351 } | |
352 | |
353 if (module->ctx_index == index) { | |
354 index++; | |
355 goto again; | |
356 } | |
357 } | |
358 } | |
359 | |
360 return index; | |
361 } |