comparison src/http/modules/perl/ngx_http_perl_module.c @ 872:1c4a5b3f9110

Axe several perl interpreter instances: they may be useful in currently unsupported threaded environment, but now they complicate code: *) perl_clone() requires at least duplicating nginx stash; *) the multiplicity requires to re-evalute all precompiled subroutines and nginx stash in new interpreter context.
author Igor Sysoev <igor@sysoev.ru>
date Sun, 26 Nov 2006 14:35:27 +0000
parents a980f66c04fb
children f92ad15c2db1
comparison
equal deleted inserted replaced
871:a980f66c04fb 872:1c4a5b3f9110
9 #include <ngx_http.h> 9 #include <ngx_http.h>
10 #include <ngx_http_perl_module.h> 10 #include <ngx_http_perl_module.h>
11 11
12 12
13 typedef struct { 13 typedef struct {
14 PerlInterpreter **free_perls;
15 ngx_uint_t interp;
16 ngx_uint_t nalloc;
17 ngx_uint_t interp_max;
18
19 PerlInterpreter *perl; 14 PerlInterpreter *perl;
20 ngx_str_t modules; 15 ngx_str_t modules;
21 ngx_array_t requires; 16 ngx_array_t requires;
22 } ngx_http_perl_main_conf_t; 17 } ngx_http_perl_main_conf_t;
23 18
43 #if (NGX_HTTP_SSI) 38 #if (NGX_HTTP_SSI)
44 static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r, 39 static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
45 ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params); 40 ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
46 #endif 41 #endif
47 42
48 static ngx_int_t
49 ngx_http_perl_get_interpreter(ngx_http_perl_main_conf_t *pmcf,
50 PerlInterpreter **perl, ngx_log_t *log);
51 static ngx_inline void
52 ngx_http_perl_free_interpreter(ngx_http_perl_main_conf_t *pmcf,
53 PerlInterpreter *perl);
54 static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf, 43 static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
55 ngx_http_perl_main_conf_t *pmcf); 44 ngx_http_perl_main_conf_t *pmcf);
56 static PerlInterpreter * 45 static PerlInterpreter *
57 ngx_http_perl_create_interpreter(ngx_http_perl_main_conf_t *pmcf, 46 ngx_http_perl_create_interpreter(ngx_http_perl_main_conf_t *pmcf,
58 ngx_log_t *log); 47 ngx_log_t *log);
70 void *child); 59 void *child);
71 static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, 60 static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd,
72 void *conf); 61 void *conf);
73 static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 62 static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
74 static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 63 static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
75 static char *ngx_http_perl_interp_max_unsupported(ngx_conf_t *cf, void *post, 64 static void ngx_http_perl_cleanup_sv(void *data);
76 void *data); 65
77 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) 66 #if (NGX_HAVE_PERL_MULTIPLICITY)
78 static void ngx_http_perl_cleanup_perl(void *data); 67 static void ngx_http_perl_cleanup_perl(void *data);
79 #endif 68 #endif
80 static void ngx_http_perl_cleanup_sv(void *data);
81
82
83 static ngx_conf_post_handler_pt ngx_http_perl_interp_max_p =
84 ngx_http_perl_interp_max_unsupported;
85 69
86 70
87 static ngx_command_t ngx_http_perl_commands[] = { 71 static ngx_command_t ngx_http_perl_commands[] = {
88 72
89 { ngx_string("perl_modules"), 73 { ngx_string("perl_modules"),
97 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, 81 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
98 ngx_http_perl_require, 82 ngx_http_perl_require,
99 NGX_HTTP_MAIN_CONF_OFFSET, 83 NGX_HTTP_MAIN_CONF_OFFSET,
100 0, 84 0,
101 NULL }, 85 NULL },
102
103 { ngx_string("perl_interp_max"),
104 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
105 ngx_conf_set_num_slot,
106 NGX_HTTP_MAIN_CONF_OFFSET,
107 offsetof(ngx_http_perl_main_conf_t, interp_max),
108 &ngx_http_perl_interp_max_p },
109 86
110 { ngx_string("perl"), 87 { ngx_string("perl"),
111 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 88 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
112 ngx_http_perl, 89 ngx_http_perl,
113 NGX_HTTP_LOC_CONF_OFFSET, 90 NGX_HTTP_LOC_CONF_OFFSET,
227 ngx_http_set_ctx(r, ctx, ngx_http_perl_module); 204 ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
228 } 205 }
229 206
230 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); 207 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
231 208
232 rc = ngx_http_perl_get_interpreter(pmcf, &ctx->perl, r->connection->log);
233
234 if (rc != NGX_OK) {
235 ngx_http_finalize_request(r, rc);
236 return;
237 }
238
239 { 209 {
240 210
241 dTHXa(ctx->perl); 211 dTHXa(pmcf->perl);
242 212
243 if (ctx->next == NULL) { 213 if (ctx->next == NULL) {
244 plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module); 214 plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
245 sub = plcf->sub; 215 sub = plcf->sub;
246 handler = &plcf->handler; 216 handler = &plcf->handler;
253 223
254 rc = ngx_http_perl_call_handler(aTHX_ r, sub, NULL, handler, NULL); 224 rc = ngx_http_perl_call_handler(aTHX_ r, sub, NULL, handler, NULL);
255 225
256 } 226 }
257 227
258 ngx_http_perl_free_interpreter(pmcf, ctx->perl);
259
260 if (rc > 600) { 228 if (rc > 600) {
261 rc = NGX_OK; 229 rc = NGX_OK;
262 } 230 }
263 231
264 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 232 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
298 uintptr_t data) 266 uintptr_t data)
299 { 267 {
300 ngx_http_perl_variable_t *pv = (ngx_http_perl_variable_t *) data; 268 ngx_http_perl_variable_t *pv = (ngx_http_perl_variable_t *) data;
301 269
302 ngx_int_t rc; 270 ngx_int_t rc;
303 ngx_uint_t recursive;
304 ngx_str_t value; 271 ngx_str_t value;
305 ngx_http_perl_ctx_t *ctx; 272 ngx_http_perl_ctx_t *ctx;
306 ngx_http_perl_main_conf_t *pmcf; 273 ngx_http_perl_main_conf_t *pmcf;
307 274
308 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 275 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
315 if (ctx == NULL) { 282 if (ctx == NULL) {
316 return NGX_ERROR; 283 return NGX_ERROR;
317 } 284 }
318 285
319 ngx_http_set_ctx(r, ctx, ngx_http_perl_module); 286 ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
320 287 }
321 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); 288
322 289 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
323 rc = ngx_http_perl_get_interpreter(pmcf, &ctx->perl,
324 r->connection->log);
325
326 if (rc != NGX_OK) {
327 return rc;
328 }
329
330 recursive = 0;
331
332 } else {
333 pmcf = NULL;
334 recursive = 1;
335 }
336 290
337 value.data = NULL; 291 value.data = NULL;
338 292
339 { 293 {
340 294
341 dTHXa(ctx->perl); 295 dTHXa(pmcf->perl);
342 296
343 rc = ngx_http_perl_call_handler(aTHX_ r, pv->sub, NULL, 297 rc = ngx_http_perl_call_handler(aTHX_ r, pv->sub, NULL,
344 &pv->handler, &value); 298 &pv->handler, &value);
345 299
346 }
347
348 if (recursive == 0) {
349 ngx_http_perl_free_interpreter(pmcf, ctx->perl);
350 } 300 }
351 301
352 if (value.data) { 302 if (value.data) {
353 v->len = value.len; 303 v->len = value.len;
354 v->valid = 1; 304 v->valid = 1;
383 ngx_http_perl_main_conf_t *pmcf; 333 ngx_http_perl_main_conf_t *pmcf;
384 334
385 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 335 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
386 "perl ssi handler"); 336 "perl ssi handler");
387 337
388 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
389
390 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); 338 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
391 339
392 if (ctx == NULL) { 340 if (ctx == NULL) {
393 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t)); 341 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
394 if (ctx == NULL) { 342 if (ctx == NULL) {
396 } 344 }
397 345
398 ngx_http_set_ctx(r, ctx, ngx_http_perl_module); 346 ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
399 } 347 }
400 348
401 rc = ngx_http_perl_get_interpreter(pmcf, &ctx->perl, r->connection->log); 349 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
402
403 if (rc != NGX_OK) {
404 return rc;
405 }
406 350
407 ctx->ssi = ssi_ctx; 351 ctx->ssi = ssi_ctx;
408 352
409 handler = params[NGX_HTTP_PERL_SSI_SUB]; 353 handler = params[NGX_HTTP_PERL_SSI_SUB];
410 handler->data[handler->len] = '\0'; 354 handler->data[handler->len] = '\0';
411 355
412 { 356 {
413 357
414 dTHXa(ctx->perl); 358 dTHXa(pmcf->perl);
415 359
416 #if 0 360 #if 0
417 361
418 /* the code is disabled to force the precompiled perl code using only */ 362 /* the code is disabled to force the precompiled perl code using only */
419 363
438 382
439 SvREFCNT_dec(sv); 383 SvREFCNT_dec(sv);
440 384
441 } 385 }
442 386
443 ngx_http_perl_free_interpreter(pmcf, ctx->perl);
444
445 ctx->filename.data = NULL; 387 ctx->filename.data = NULL;
446 ctx->redirect_uri.len = 0; 388 ctx->redirect_uri.len = 0;
447 ctx->ssi = NULL; 389 ctx->ssi = NULL;
448 390
449 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl ssi done"); 391 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl ssi done");
452 } 394 }
453 395
454 #endif 396 #endif
455 397
456 398
457 static ngx_int_t
458 ngx_http_perl_get_interpreter(ngx_http_perl_main_conf_t *pmcf,
459 PerlInterpreter **perl, ngx_log_t *log)
460 {
461 if (pmcf->interp) {
462 pmcf->interp--;
463
464 *perl = pmcf->free_perls[pmcf->interp];
465
466 return NGX_OK;
467 }
468
469 if (pmcf->nalloc < pmcf->interp_max) {
470 *perl = ngx_http_perl_create_interpreter(pmcf, log);
471
472 if (*perl) {
473 return NGX_OK;
474 }
475
476 return NGX_HTTP_INTERNAL_SERVER_ERROR;
477 }
478
479 ngx_log_error(NGX_LOG_ALERT, log, 0, "no free perl interpreter");
480
481 return NGX_HTTP_SERVICE_UNAVAILABLE;
482 }
483
484
485 static ngx_inline void
486 ngx_http_perl_free_interpreter(ngx_http_perl_main_conf_t *pmcf,
487 PerlInterpreter *perl)
488 {
489 pmcf->free_perls[pmcf->interp++] = perl;
490 }
491
492
493 static char * 399 static char *
494 ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) 400 ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
495 { 401 {
496 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) 402 #if (NGX_HAVE_PERL_MULTIPLICITY)
497 ngx_pool_cleanup_t *cln; 403 ngx_pool_cleanup_t *cln;
498 404
499 cln = ngx_pool_cleanup_add(cf->pool, 0); 405 cln = ngx_pool_cleanup_add(cf->pool, 0);
500 if (cln == NULL) { 406 if (cln == NULL) {
501 return NGX_CONF_ERROR; 407 return NGX_CONF_ERROR;
515 if (ngx_conf_full_name(cf->cycle, &pmcf->modules) != NGX_OK) { 421 if (ngx_conf_full_name(cf->cycle, &pmcf->modules) != NGX_OK) {
516 return NGX_CONF_ERROR; 422 return NGX_CONF_ERROR;
517 } 423 }
518 } 424 }
519 425
520 #if !(NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) 426 #if !(NGX_HAVE_PERL_MULTIPLICITY)
521 427
522 if (perl) { 428 if (perl) {
523 if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) 429 if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log)
524 != NGX_OK) 430 != NGX_OK)
525 { 431 {
540 if (pmcf->perl == NULL) { 446 if (pmcf->perl == NULL) {
541 PERL_SYS_TERM(); 447 PERL_SYS_TERM();
542 return NGX_CONF_ERROR; 448 return NGX_CONF_ERROR;
543 } 449 }
544 450
545 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) 451 #if (NGX_HAVE_PERL_MULTIPLICITY)
546 452
547 cln->handler = ngx_http_perl_cleanup_perl; 453 cln->handler = ngx_http_perl_cleanup_perl;
548 cln->data = pmcf->perl; 454 cln->data = pmcf->perl;
549 455
550 #else 456 #else
567 char *ver, *embedding[6]; 473 char *ver, *embedding[6];
568 PerlInterpreter *perl; 474 PerlInterpreter *perl;
569 475
570 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "create perl interpreter"); 476 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "create perl interpreter");
571 477
572 #if (NGX_HAVE_PERL_CLONE)
573
574 if (pmcf->perl) {
575
576 perl = perl_clone(pmcf->perl, CLONEf_KEEP_PTR_TABLE);
577 if (perl == NULL) {
578 ngx_log_error(NGX_LOG_ALERT, log, 0, "perl_clone() failed");
579 return NULL;
580 }
581
582 {
583
584 dTHXa(perl);
585
586 ptr_table_free(PL_ptr_table);
587 PL_ptr_table = NULL;
588
589 }
590
591 pmcf->nalloc++;
592
593 return perl;
594 }
595
596 #endif
597
598 perl = perl_alloc(); 478 perl = perl_alloc();
599 if (perl == NULL) { 479 if (perl == NULL) {
600 ngx_log_error(NGX_LOG_ALERT, log, 0, "perl_alloc() failed"); 480 ngx_log_error(NGX_LOG_ALERT, log, 0, "perl_alloc() failed");
601 return NULL; 481 return NULL;
602 } 482 }
646 if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, log) != NGX_OK) { 526 if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, log) != NGX_OK) {
647 goto fail; 527 goto fail;
648 } 528 }
649 529
650 } 530 }
651
652 pmcf->nalloc++;
653 531
654 return perl; 532 return perl;
655 533
656 fail: 534 fail:
657 535
822 pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t)); 700 pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t));
823 if (pmcf == NULL) { 701 if (pmcf == NULL) {
824 return NGX_CONF_ERROR; 702 return NGX_CONF_ERROR;
825 } 703 }
826 704
827 pmcf->interp_max = NGX_CONF_UNSET_UINT;
828
829 if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *)) 705 if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *))
830 != NGX_OK) 706 != NGX_OK)
831 { 707 {
832 return NULL; 708 return NULL;
833 } 709 }
839 static char * 715 static char *
840 ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf) 716 ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf)
841 { 717 {
842 ngx_http_perl_main_conf_t *pmcf = conf; 718 ngx_http_perl_main_conf_t *pmcf = conf;
843 719
844 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY)
845 ngx_conf_init_uint_value(pmcf->interp_max, 10);
846 #else
847 ngx_conf_init_uint_value(pmcf->interp_max, 1);
848 #endif
849
850 pmcf->free_perls = ngx_pcalloc(cf->pool,
851 pmcf->interp_max * sizeof(PerlInterpreter *));
852 if (pmcf->free_perls == NULL) {
853 return NGX_CONF_ERROR;
854 }
855
856 if (pmcf->perl == NULL) { 720 if (pmcf->perl == NULL) {
857 if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) { 721 if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
858 return NGX_CONF_ERROR; 722 return NGX_CONF_ERROR;
859 } 723 }
860 } 724 }
861 725
862 #if !(NGX_HAVE_PERL_CLONE)
863 ngx_http_perl_free_interpreter(pmcf, pmcf->perl);
864 #endif
865
866 return NGX_CONF_OK; 726 return NGX_CONF_OK;
867 } 727 }
868 728
869 729
870 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY) 730 #if (NGX_HAVE_PERL_MULTIPLICITY)
871 731
872 static void 732 static void
873 ngx_http_perl_cleanup_perl(void *data) 733 ngx_http_perl_cleanup_perl(void *data)
874 { 734 {
875 PerlInterpreter *perl = data; 735 PerlInterpreter *perl = data;
1121 v->get_handler = ngx_http_perl_variable; 981 v->get_handler = ngx_http_perl_variable;
1122 v->data = (uintptr_t) pv; 982 v->data = (uintptr_t) pv;
1123 983
1124 return NGX_CONF_OK; 984 return NGX_CONF_OK;
1125 } 985 }
1126
1127
1128 static char *
1129 ngx_http_perl_interp_max_unsupported(ngx_conf_t *cf, void *post, void *data)
1130 {
1131 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY)
1132
1133 return NGX_CONF_OK;
1134
1135 #else
1136
1137 return "to use perl_interp_max you have to build perl with "
1138 "-Dusemultiplicity or -Dusethreads options";
1139
1140 #endif
1141 }