Nginx学习笔记(六) 源码分析&启动过程
Nginx的启动过程
主要介绍Nginx的启动过程,可以在/core/nginx.c中找到Nginx的主函数main(),那么就从这里开始分析Nginx的启动过程。
涉及到的基本函数
源码:
1 /* 2 * Copyright (C) Igor Sysoev 3 * Copyright (C) Nginx, Inc. 4 */ 5 6 7 #include <ngx_config.h> 8 #include <ngx_core.h> 9 #include <nginx.h> 10 11 12 static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); 13 static ngx_int_t ngx_get_options(int argc, char *const *argv); 14 static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); 15 static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv); 16 static void *ngx_core_module_create_conf(ngx_cycle_t *cycle); 17 static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf); 18 static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 19 static char *ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 20 static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 21 static char *ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, 22 void *conf); 23 static char *ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, 24 void *conf); 25 26 27 static ngx_conf_enum_t ngx_debug_points[] = { 28 { ngx_string("stop"), NGX_DEBUG_POINTS_STOP }, 29 { ngx_string("abort"), NGX_DEBUG_POINTS_ABORT }, 30 { ngx_null_string, 0 } 31 }; 32 33 34 static ngx_command_t ngx_core_commands[] = { 35 36 { ngx_string("daemon"), 37 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, 38 ngx_conf_set_flag_slot, 39 0, 40 offsetof(ngx_core_conf_t, daemon), 41 NULL }, 42 43 { ngx_string("master_process"), 44 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG, 45 ngx_conf_set_flag_slot, 46 0, 47 offsetof(ngx_core_conf_t, master), 48 NULL }, 49 50 { ngx_string("timer_resolution"), 51 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 52 ngx_conf_set_msec_slot, 53 0, 54 offsetof(ngx_core_conf_t, timer_resolution), 55 NULL }, 56 57 { ngx_string("pid"), 58 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 59 ngx_conf_set_str_slot, 60 0, 61 offsetof(ngx_core_conf_t, pid), 62 NULL }, 63 64 { ngx_string("lock_file"), 65 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 66 ngx_conf_set_str_slot, 67 0, 68 offsetof(ngx_core_conf_t, lock_file), 69 NULL }, 70 71 { ngx_string("worker_processes"), 72 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 73 ngx_set_worker_processes, 74 0, 75 0, 76 NULL }, 77 78 { ngx_string("debug_points"), 79 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 80 ngx_conf_set_enum_slot, 81 0, 82 offsetof(ngx_core_conf_t, debug_points), 83 &ngx_debug_points }, 84 85 { ngx_string("user"), 86 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12, 87 ngx_set_user, 88 0, 89 0, 90 NULL }, 91 92 { ngx_string("worker_priority"), 93 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 94 ngx_set_priority, 95 0, 96 0, 97 NULL }, 98 99 { ngx_string("worker_cpu_affinity"), 100 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_1MORE, 101 ngx_set_cpu_affinity, 102 0, 103 0, 104 NULL }, 105 106 { ngx_string("worker_rlimit_nofile"), 107 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 108 ngx_conf_set_num_slot, 109 0, 110 offsetof(ngx_core_conf_t, rlimit_nofile), 111 NULL }, 112 113 { ngx_string("worker_rlimit_core"), 114 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 115 ngx_conf_set_off_slot, 116 0, 117 offsetof(ngx_core_conf_t, rlimit_core), 118 NULL }, 119 120 { ngx_string("worker_rlimit_sigpending"), 121 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 122 ngx_conf_set_num_slot, 123 0, 124 offsetof(ngx_core_conf_t, rlimit_sigpending), 125 NULL }, 126 127 { ngx_string("working_directory"), 128 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 129 ngx_conf_set_str_slot, 130 0, 131 offsetof(ngx_core_conf_t, working_directory), 132 NULL }, 133 134 { ngx_string("env"), 135 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 136 ngx_set_env, 137 0, 138 0, 139 NULL }, 140 141 #if (NGX_THREADS) 142 143 { ngx_string("worker_threads"), 144 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 145 ngx_conf_set_num_slot, 146 0, 147 offsetof(ngx_core_conf_t, worker_threads), 148 NULL }, 149 150 { ngx_string("thread_stack_size"), 151 NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 152 ngx_conf_set_size_slot, 153 0, 154 offsetof(ngx_core_conf_t, thread_stack_size), 155 NULL }, 156 157 #endif 158 159 ngx_null_command 160 }; 161 162 163 static ngx_core_module_t ngx_core_module_ctx = { 164 ngx_string("core"), 165 ngx_core_module_create_conf, 166 ngx_core_module_init_conf 167 }; 168 169 170 ngx_module_t ngx_core_module = { 171 NGX_MODULE_V1, 172 &ngx_core_module_ctx, /* module context */ 173 ngx_core_commands, /* module directives */ 174 NGX_CORE_MODULE, /* module type */ 175 NULL, /* init master */ 176 NULL, /* init module */ 177 NULL, /* init process */ 178 NULL, /* init thread */ 179 NULL, /* exit thread */ 180 NULL, /* exit process */ 181 NULL, /* exit master */ 182 NGX_MODULE_V1_PADDING 183 }; 184 185 186 ngx_uint_t ngx_max_module; 187 188 static ngx_uint_t ngx_show_help; 189 static ngx_uint_t ngx_show_version; 190 static ngx_uint_t ngx_show_configure; 191 static u_char *ngx_prefix; 192 static u_char *ngx_conf_file; 193 static u_char *ngx_conf_params; 194 static char *ngx_signal; 195 196 197 static char **ngx_os_environ; 198 199 200 int ngx_cdecl 201 main(int argc, char *const *argv) 202 { 203 ngx_int_t i; 204 ngx_log_t *log; 205 ngx_cycle_t *cycle, init_cycle; 206 ngx_core_conf_t *ccf; 207 208 ngx_debug_init(); 209 210 if (ngx_strerror_init() != NGX_OK) { 211 return 1; 212 } 213 214 if (ngx_get_options(argc, argv) != NGX_OK) { 215 return 1; 216 } 217 218 if (ngx_show_version) { 219 ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED); 220 221 if (ngx_show_help) { 222 ngx_write_stderr( 223 "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " 224 "[-p prefix] [-g directives]" NGX_LINEFEED 225 NGX_LINEFEED 226 "Options:" NGX_LINEFEED 227 " -?,-h : this help" NGX_LINEFEED 228 " -v : show version and exit" NGX_LINEFEED 229 " -V : show version and configure options then exit" 230 NGX_LINEFEED 231 " -t : test configuration and exit" NGX_LINEFEED 232 " -q : suppress non-error messages " 233 "during configuration testing" NGX_LINEFEED 234 " -s signal : send signal to a master process: " 235 "stop, quit, reopen, reload" NGX_LINEFEED 236 #ifdef NGX_PREFIX 237 " -p prefix : set prefix path (default: " 238 NGX_PREFIX ")" NGX_LINEFEED 239 #else 240 " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED 241 #endif 242 " -c filename : set configuration file (default: " 243 NGX_CONF_PATH ")" NGX_LINEFEED 244 " -g directives : set global directives out of configuration " 245 "file" NGX_LINEFEED NGX_LINEFEED 246 ); 247 } 248 249 if (ngx_show_configure) { 250 ngx_write_stderr( 251 #ifdef NGX_COMPILER 252 "built by " NGX_COMPILER NGX_LINEFEED 253 #endif 254 #if (NGX_SSL) 255 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME 256 "TLS SNI support enabled" NGX_LINEFEED 257 #else 258 "TLS SNI support disabled" NGX_LINEFEED 259 #endif 260 #endif 261 "configure arguments:" NGX_CONFIGURE NGX_LINEFEED); 262 } 263 264 if (!ngx_test_config) { 265 return 0; 266 } 267 } 268 269 /* TODO */ ngx_max_sockets = -1; 270 271 ngx_time_init(); 272 273 #if (NGX_PCRE) 274 ngx_regex_init(); 275 #endif 276 277 ngx_pid = ngx_getpid(); 278 279 log = ngx_log_init(ngx_prefix); 280 if (log == NULL) { 281 return 1; 282 } 283 284 /* STUB */ 285 #if (NGX_OPENSSL) 286 ngx_ssl_init(log); 287 #endif 288 289 /* 290 * init_cycle->log is required for signal handlers and 291 * ngx_process_options() 292 */ 293 294 ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); 295 init_cycle.log = log; 296 ngx_cycle = &init_cycle; 297 298 init_cycle.pool = ngx_create_pool(1024, log); 299 if (init_cycle.pool == NULL) { 300 return 1; 301 } 302 303 if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { 304 return 1; 305 } 306 307 if (ngx_process_options(&init_cycle) != NGX_OK) { 308 return 1; 309 } 310 311 if (ngx_os_init(log) != NGX_OK) { 312 return 1; 313 } 314 315 /* 316 * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init() 317 */ 318 319 if (ngx_crc32_table_init() != NGX_OK) { 320 return 1; 321 } 322 323 if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { 324 return 1; 325 } 326 327 ngx_max_module = 0; 328 for (i = 0; ngx_modules[i]; i++) { 329 ngx_modules[i]->index = ngx_max_module++; 330 } 331 332 cycle = ngx_init_cycle(&init_cycle); 333 if (cycle == NULL) { 334 if (ngx_test_config) { 335 ngx_log_stderr(0, "configuration file %s test failed", 336 init_cycle.conf_file.data); 337 } 338 339 return 1; 340 } 341 342 if (ngx_test_config) { 343 if (!ngx_quiet_mode) { 344 ngx_log_stderr(0, "configuration file %s test is successful", 345 cycle->conf_file.data); 346 } 347 348 return 0; 349 } 350 351 if (ngx_signal) { 352 return ngx_signal_process(cycle, ngx_signal); 353 } 354 355 ngx_os_status(cycle->log); 356 357 ngx_cycle = cycle; 358 359 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); 360 361 if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { 362 ngx_process = NGX_PROCESS_MASTER; 363 } 364 365 #if !(NGX_WIN32) 366 367 if (ngx_init_signals(cycle->log) != NGX_OK) { 368 return 1; 369 } 370 371 if (!ngx_inherited && ccf->daemon) { 372 if (ngx_daemon(cycle->log) != NGX_OK) { 373 return 1; 374 } 375 376 ngx_daemonized = 1; 377 } 378 379 if (ngx_inherited) { 380 ngx_daemonized = 1; 381 } 382 383 #endif 384 385 if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { 386 return 1; 387 } 388 389 if (cycle->log->file->fd != ngx_stderr) { 390 391 if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { 392 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, 393 ngx_set_stderr_n " failed"); 394 return 1; 395 } 396 } 397 398 if (log->file->fd != ngx_stderr) { 399 if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) { 400 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, 401 ngx_close_file_n " built-in log failed"); 402 } 403 } 404 405 ngx_use_stderr = 0; 406 407 if (ngx_process == NGX_PROCESS_SINGLE) { 408 ngx_single_process_cycle(cycle); 409 410 } else { 411 ngx_master_process_cycle(cycle); 412 } 413 414 return 0; 415 } 416 417 418 static ngx_int_t 419 ngx_add_inherited_sockets(ngx_cycle_t *cycle) 420 { 421 u_char *p, *v, *inherited; 422 ngx_int_t s; 423 ngx_listening_t *ls; 424 425 inherited = (u_char *) getenv(NGINX_VAR); 426 427 if (inherited == NULL) { 428 return NGX_OK; 429 } 430 431 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, 432 "using inherited sockets from \"%s\"", inherited); 433 434 if (ngx_array_init(&cycle->listening, cycle->pool, 10, 435 sizeof(ngx_listening_t)) 436 != NGX_OK) 437 { 438 return NGX_ERROR; 439 } 440 441 for (p = inherited, v = p; *p; p++) { 442 if (*p == ':' || *p == ';') { 443 s = ngx_atoi(v, p - v); 444 if (s == NGX_ERROR) { 445 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, 446 "invalid socket number \"%s\" in " NGINX_VAR 447 " environment variable, ignoring the rest" 448 " of the variable", v); 449 break; 450 } 451 452 v = p + 1; 453 454 ls = ngx_array_push(&cycle->listening); 455 if (ls == NULL) { 456 return NGX_ERROR; 457 } 458 459 ngx_memzero(ls, sizeof(ngx_listening_t)); 460 461 ls->fd = (ngx_socket_t) s; 462 } 463 } 464 465 ngx_inherited = 1; 466 467 return ngx_set_inherited_sockets(cycle); 468 } 469 470 471 char ** 472 ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last) 473 { 474 char **p, **env; 475 ngx_str_t *var; 476 ngx_uint_t i, n; 477 ngx_core_conf_t *ccf; 478 479 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); 480 481 if (last == NULL && ccf->environment) { 482 return ccf->environment; 483 } 484 485 var = ccf->env.elts; 486 487 for (i = 0; i < ccf->env.nelts; i++) { 488 if (ngx_strcmp(var[i].data, "TZ") == 0 489 || ngx_strncmp(var[i].data, "TZ=", 3) == 0) 490 { 491 goto tz_found; 492 } 493 } 494 495 var = ngx_array_push(&ccf->env); 496 if (var == NULL) { 497 return NULL; 498 } 499 500 var->len = 2; 501 var->data = (u_char *) "TZ"; 502 503 var = ccf->env.elts; 504 505 tz_found: 506 507 n = 0; 508 509 for (i = 0; i < ccf->env.nelts; i++) { 510 511 if (var[i].data[var[i].len] == '=') { 512 n++; 513 continue; 514 } 515 516 for (p = ngx_os_environ; *p; p++) { 517 518 if (ngx_strncmp(*p, var[i].data, var[i].len) == 0 519 && (*p)[var[i].len] == '=') 520 { 521 n++; 522 break; 523 } 524 } 525 } 526 527 if (last) { 528 env = ngx_alloc((*last + n + 1) * sizeof(char *), cycle->log); 529 *last = n; 530 531 } else { 532 env = ngx_palloc(cycle->pool, (n + 1) * sizeof(char *)); 533 } 534 535 if (env == NULL) { 536 return NULL; 537 } 538 539 n = 0; 540 541 for (i = 0; i < ccf->env.nelts; i++) { 542 543 if (var[i].data[var[i].len] == '=') { 544 env[n++] = (char *) var[i].data; 545 continue; 546 } 547 548 for (p = ngx_os_environ; *p; p++) { 549 550 if (ngx_strncmp(*p, var[i].data, var[i].len) == 0 551 && (*p)[var[i].len] == '=') 552 { 553 env[n++] = *p; 554 break; 555 } 556 } 557 } 558 559 env[n] = NULL; 560 561 if (last == NULL) { 562 ccf->environment = env; 563 environ = env; 564 } 565 566 return env; 567 } 568 569 570 ngx_pid_t 571 ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) 572 { 573 char **env, *var; 574 u_char *p; 575 ngx_uint_t i, n; 576 ngx_pid_t pid; 577 ngx_exec_ctx_t ctx; 578 ngx_core_conf_t *ccf; 579 ngx_listening_t *ls; 580 581 ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t)); 582 583 ctx.path = argv[0]; 584 ctx.name = "new binary process"; 585 ctx.argv = argv; 586 587 n = 2; 588 env = ngx_set_environment(cycle, &n); 589 if (env == NULL) { 590 return NGX_INVALID_PID; 591 } 592 593 var = ngx_alloc(sizeof(NGINX_VAR) 594 + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, 595 cycle->log); 596 if (var == NULL) { 597 ngx_free(env); 598 return NGX_INVALID_PID; 599 } 600 601 p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR)); 602 603 ls = cycle->listening.elts; 604 for (i = 0; i < cycle->listening.nelts; i++) { 605 p = ngx_sprintf(p, "%ud;", ls[i].fd); 606 } 607 608 *p = '\0'; 609 610 env[n++] = var; 611 612 #if (NGX_SETPROCTITLE_USES_ENV) 613 614 /* allocate the spare 300 bytes for the new binary process title */ 615 616 env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 617 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 618 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 619 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 620 "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 621 622 #endif 623 624 env[n] = NULL; 625 626 #if (NGX_DEBUG) 627 { 628 char **e; 629 for (e = env; *e; e++) { 630 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e); 631 } 632 } 633 #endif 634 635 ctx.envp = (char *const *) env; 636 637 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); 638 639 if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) { 640 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, 641 ngx_rename_file_n " %s to %s failed " 642 "before executing new binary process \"%s\"", 643 ccf->pid.data, ccf->oldpid.data, argv[0]); 644 645 ngx_free(env); 646 ngx_free(var); 647 648 return NGX_INVALID_PID; 649 } 650 651 pid = ngx_execute(cycle, &ctx); 652 653 if (pid == NGX_INVALID_PID) { 654 if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) 655 == NGX_FILE_ERROR) 656 { 657 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, 658 ngx_rename_file_n " %s back to %s failed after " 659 "an attempt to execute new binary process \"%s\"", 660 ccf->oldpid.data, ccf->pid.data, argv[0]); 661 } 662 } 663 664 ngx_free(env); 665 ngx_free(var); 666 667 return pid; 668 } 669 670 671 static ngx_int_t 672 ngx_get_options(int argc, char *const *argv) 673 { 674 u_char *p; 675 ngx_int_t i; 676 677 for (i = 1; i < argc; i++) { 678 679 p = (u_char *) argv[i]; 680 681 if (*p++ != '-') { 682 ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]); 683 return NGX_ERROR; 684 } 685 686 while (*p) { 687 688 switch (*p++) { 689 690 case '?': 691 case 'h': 692 ngx_show_version = 1; 693 ngx_show_help = 1; 694 break; 695 696 case 'v': 697 ngx_show_version = 1; 698 break; 699 700 case 'V': 701 ngx_show_version = 1; 702 ngx_show_configure = 1; 703 break; 704 705 case 't': 706 ngx_test_config = 1; 707 break; 708 709 case 'q': 710 ngx_quiet_mode = 1; 711 break; 712 713 case 'p': 714 if (*p) { 715 ngx_prefix = p; 716 goto next; 717 } 718 719 if (argv[++i]) { 720 ngx_prefix = (u_char *) argv[i]; 721 goto next; 722 } 723 724 ngx_log_stderr(0, "option \"-p\" requires directory name"); 725 return NGX_ERROR; 726 727 case 'c': 728 if (*p) { 729 ngx_conf_file = p; 730 goto next; 731 } 732 733 if (argv[++i]) { 734 ngx_conf_file = (u_char *) argv[i]; 735 goto next; 736 } 737 738 ngx_log_stderr(0, "option \"-c\" requires file name"); 739 return NGX_ERROR; 740 741 case 'g': 742 if (*p) { 743 ngx_conf_params = p; 744 goto next; 745 } 746 747 if (argv[++i]) { 748 ngx_conf_params = (u_char *) argv[i]; 749 goto next; 750 } 751 752 ngx_log_stderr(0, "option \"-g\" requires parameter"); 753 return NGX_ERROR; 754 755 case 's': 756 if (*p) { 757 ngx_signal = (char *) p; 758 759 } else if (argv[++i]) { 760 ngx_signal = argv[i]; 761 762 } else { 763 ngx_log_stderr(0, "option \"-s\" requires parameter"); 764 return NGX_ERROR; 765 } 766 767 if (ngx_strcmp(ngx_signal, "stop") == 0 768 || ngx_strcmp(ngx_signal, "quit") == 0 769 || ngx_strcmp(ngx_signal, "reopen") == 0 770 || ngx_strcmp(ngx_signal, "reload") == 0) 771 { 772 ngx_process = NGX_PROCESS_SIGNALLER; 773 goto next; 774 } 775 776 ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal); 777 return NGX_ERROR; 778 779 default: 780 ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1)); 781 return NGX_ERROR; 782 } 783 } 784 785 next: 786 787 continue; 788 } 789 790 return NGX_OK; 791 } 792 793 794 static ngx_int_t 795 ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv) 796 { 797 #if (NGX_FREEBSD) 798 799 ngx_os_argv = (char **) argv; 800 ngx_argc = argc; 801 ngx_argv = (char **) argv; 802 803 #else 804 size_t len; 805 ngx_int_t i; 806 807 ngx_os_argv = (char **) argv; 808 ngx_argc = argc; 809 810 ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log); 811 if (ngx_argv == NULL) { 812 return NGX_ERROR; 813 } 814 815 for (i = 0; i < argc; i++) { 816 len = ngx_strlen(argv[i]) + 1; 817 818 ngx_argv[i] = ngx_alloc(len, cycle->log); 819 if (ngx_argv[i] == NULL) { 820 return NGX_ERROR; 821 } 822 823 (void) ngx_cpystrn((u_char *) ngx_argv[i], (u_char *) argv[i], len); 824 } 825 826 ngx_argv[i] = NULL; 827 828 #endif 829 830 ngx_os_environ = environ; 831 832 return NGX_OK; 833 } 834 835 836 static ngx_int_t 837 ngx_process_options(ngx_cycle_t *cycle) 838 { 839 u_char *p; 840 size_t len; 841 842 if (ngx_prefix) { 843 len = ngx_strlen(ngx_prefix); 844 p = ngx_prefix; 845 846 if (len && !ngx_path_separator(p[len - 1])) { 847 p = ngx_pnalloc(cycle->pool, len + 1); 848 if (p == NULL) { 849 return NGX_ERROR; 850 } 851 852 ngx_memcpy(p, ngx_prefix, len); 853 p[len++] = '/'; 854 } 855 856 cycle->conf_prefix.len = len; 857 cycle->conf_prefix.data = p; 858 cycle->prefix.len = len; 859 cycle->prefix.data = p; 860 861 } else { 862 863 #ifndef NGX_PREFIX 864 865 p = ngx_pnalloc(cycle->pool, NGX_MAX_PATH); 866 if (p == NULL) { 867 return NGX_ERROR; 868 } 869 870 if (ngx_getcwd(p, NGX_MAX_PATH) == 0) { 871 ngx_log_stderr(ngx_errno, "[emerg]: " ngx_getcwd_n " failed"); 872 return NGX_ERROR; 873 } 874 875 len = ngx_strlen(p); 876 877 p[len++] = '/'; 878 879 cycle->conf_prefix.len = len; 880 cycle->conf_prefix.data = p; 881 cycle->prefix.len = len; 882 cycle->prefix.data = p; 883 884 #else 885 886 #ifdef NGX_CONF_PREFIX 887 ngx_str_set(&cycle->conf_prefix, NGX_CONF_PREFIX); 888 #else 889 ngx_str_set(&cycle->conf_prefix, NGX_PREFIX); 890 #endif 891 ngx_str_set(&cycle->prefix, NGX_PREFIX); 892 893 #endif 894 } 895 896 if (ngx_conf_file) { 897 cycle->conf_file.len = ngx_strlen(ngx_conf_file); 898 cycle->conf_file.data = ngx_conf_file; 899 900 } else { 901 ngx_str_set(&cycle->conf_file, NGX_CONF_PATH); 902 } 903 904 if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) { 905 return NGX_ERROR; 906 } 907 908 for (p = cycle->conf_file.data + cycle->conf_file.len - 1; 909 p > cycle->conf_file.data; 910 p--) 911 { 912 if (ngx_path_separator(*p)) { 913 cycle->conf_prefix.len = p - ngx_cycle->conf_file.data + 1; 914 cycle->conf_prefix.data = ngx_cycle->conf_file.data; 915 break; 916 } 917 } 918 919 if (ngx_conf_params) { 920 cycle->conf_param.len = ngx_strlen(ngx_conf_params); 921 cycle->conf_param.data = ngx_conf_params; 922 } 923 924 if (ngx_test_config) { 925 cycle->log->log_level = NGX_LOG_INFO; 926 } 927 928 return NGX_OK; 929 } 930 931 932 static void * 933 ngx_core_module_create_conf(ngx_cycle_t *cycle) 934 { 935 ngx_core_conf_t *ccf; 936 937 ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)); 938 if (ccf == NULL) { 939 return NULL; 940 } 941 942 /* 943 * set by ngx_pcalloc() 944 * 945 * ccf->pid = NULL; 946 * ccf->oldpid = NULL; 947 * ccf->priority = 0; 948 * ccf->cpu_affinity_n = 0; 949 * ccf->cpu_affinity = NULL; 950 */ 951 952 ccf->daemon = NGX_CONF_UNSET; 953 ccf->master = NGX_CONF_UNSET; 954 ccf->timer_resolution = NGX_CONF_UNSET_MSEC; 955 956 ccf->worker_processes = NGX_CONF_UNSET; 957 ccf->debug_points = NGX_CONF_UNSET; 958 959 ccf->rlimit_nofile = NGX_CONF_UNSET; 960 ccf->rlimit_core = NGX_CONF_UNSET; 961 ccf->rlimit_sigpending = NGX_CONF_UNSET; 962 963 ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT; 964 ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT; 965 966 #if (NGX_THREADS) 967 ccf->worker_threads = NGX_CONF_UNSET; 968 ccf->thread_stack_size = NGX_CONF_UNSET_SIZE; 969 #endif 970 971 if (ngx_array_init(&ccf->env, cycle->pool, 1, sizeof(ngx_str_t)) 972 != NGX_OK) 973 { 974 return NULL; 975 } 976 977 return ccf; 978 } 979 980 981 static char * 982 ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf) 983 { 984 ngx_core_conf_t *ccf = conf; 985 986 ngx_conf_init_value(ccf->daemon, 1); 987 ngx_conf_init_value(ccf->master, 1); 988 ngx_conf_init_msec_value(ccf->timer_resolution, 0); 989 990 ngx_conf_init_value(ccf->worker_processes, 1); 991 ngx_conf_init_value(ccf->debug_points, 0); 992 993 #if (NGX_HAVE_CPU_AFFINITY) 994 995 if (ccf->cpu_affinity_n 996 && ccf->cpu_affinity_n != 1 997 && ccf->cpu_affinity_n != (ngx_uint_t) ccf->worker_processes) 998 { 999 ngx_log_error(NGX_LOG_WARN, cycle->log, 0, 1000 "the number of \"worker_processes\" is not equal to " 1001 "the number of \"worker_cpu_affinity\" masks, " 1002 "using last mask for remaining worker processes"); 1003 } 1004 1005 #endif 1006 1007 #if (NGX_THREADS) 1008 1009 ngx_conf_init_value(ccf->worker_threads, 0); 1010 ngx_threads_n = ccf->worker_threads; 1011 ngx_conf_init_size_value(ccf->thread_stack_size, 2 * 1024 * 1024); 1012 1013 #endif 1014 1015 1016 if (ccf->pid.len == 0) { 1017 ngx_str_set(&ccf->pid, NGX_PID_PATH); 1018 } 1019 1020 if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { 1021 return NGX_CONF_ERROR; 1022 } 1023 1024 ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); 1025 1026 ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); 1027 if (ccf->oldpid.data == NULL) { 1028 return NGX_CONF_ERROR; 1029 } 1030 1031 ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), 1032 NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); 1033 1034 1035 #if !(NGX_WIN32) 1036 1037 if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) { 1038 struct group *grp; 1039 struct passwd *pwd; 1040 1041 ngx_set_errno(0); 1042 pwd = getpwnam(NGX_USER); 1043 if (pwd == NULL) { 1044 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, 1045 "getpwnam(\"" NGX_USER "\") failed"); 1046 return NGX_CONF_ERROR; 1047 } 1048 1049 ccf->username = NGX_USER; 1050 ccf->user = pwd->pw_uid; 1051 1052 ngx_set_errno(0); 1053 grp = getgrnam(NGX_GROUP); 1054 if (grp == NULL) { 1055 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, 1056 "getgrnam(\"" NGX_GROUP "\") failed"); 1057 return NGX_CONF_ERROR; 1058 } 1059 1060 ccf->group = grp->gr_gid; 1061 } 1062 1063 1064 if (ccf->lock_file.len == 0) { 1065 ngx_str_set(&ccf->lock_file, NGX_LOCK_PATH); 1066 } 1067 1068 if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) != NGX_OK) { 1069 return NGX_CONF_ERROR; 1070 } 1071 1072 { 1073 ngx_str_t lock_file; 1074 1075 lock_file = cycle->old_cycle->lock_file; 1076 1077 if (lock_file.len) { 1078 lock_file.len--; 1079 1080 if (ccf->lock_file.len != lock_file.len 1081 || ngx_strncmp(ccf->lock_file.data, lock_file.data, lock_file.len) 1082 != 0) 1083 { 1084 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, 1085 "\"lock_file\" could not be changed, ignored"); 1086 } 1087 1088 cycle->lock_file.len = lock_file.len + 1; 1089 lock_file.len += sizeof(".accept"); 1090 1091 cycle->lock_file.data = ngx_pstrdup(cycle->pool, &lock_file); 1092 if (cycle->lock_file.data == NULL) { 1093 return NGX_CONF_ERROR; 1094 } 1095 1096 } else { 1097 cycle->lock_file.len = ccf->lock_file.len + 1; 1098 cycle->lock_file.data = ngx_pnalloc(cycle->pool, 1099 ccf->lock_file.len + sizeof(".accept")); 1100 if (cycle->lock_file.data == NULL) { 1101 return NGX_CONF_ERROR; 1102 } 1103 1104 ngx_memcpy(ngx_cpymem(cycle->lock_file.data, ccf->lock_file.data, 1105 ccf->lock_file.len), 1106 ".accept", sizeof(".accept")); 1107 } 1108 } 1109 1110 #endif 1111 1112 return NGX_CONF_OK; 1113 } 1114 1115 1116 static char * 1117 ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1118 { 1119 #if (NGX_WIN32) 1120 1121 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 1122 "\"user\" is not supported, ignored"); 1123 1124 return NGX_CONF_OK; 1125 1126 #else 1127 1128 ngx_core_conf_t *ccf = conf; 1129 1130 char *group; 1131 struct passwd *pwd; 1132 struct group *grp; 1133 ngx_str_t *value; 1134 1135 if (ccf->user != (uid_t) NGX_CONF_UNSET_UINT) { 1136 return "is duplicate"; 1137 } 1138 1139 if (geteuid() != 0) { 1140 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 1141 "the \"user\" directive makes sense only " 1142 "if the master process runs " 1143 "with super-user privileges, ignored"); 1144 return NGX_CONF_OK; 1145 } 1146 1147 value = (ngx_str_t *) cf->args->elts; 1148 1149 ccf->username = (char *) value[1].data; 1150 1151 ngx_set_errno(0); 1152 pwd = getpwnam((const char *) value[1].data); 1153 if (pwd == NULL) { 1154 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, 1155 "getpwnam(\"%s\") failed", value[1].data); 1156 return NGX_CONF_ERROR; 1157 } 1158 1159 ccf->user = pwd->pw_uid; 1160 1161 group = (char *) ((cf->args->nelts == 2) ? value[1].data : value[2].data); 1162 1163 ngx_set_errno(0); 1164 grp = getgrnam(group); 1165 if (grp == NULL) { 1166 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, 1167 "getgrnam(\"%s\") failed", group); 1168 return NGX_CONF_ERROR; 1169 } 1170 1171 ccf->group = grp->gr_gid; 1172 1173 return NGX_CONF_OK; 1174 1175 #endif 1176 } 1177 1178 1179 static char * 1180 ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1181 { 1182 ngx_core_conf_t *ccf = conf; 1183 1184 ngx_str_t *value, *var; 1185 ngx_uint_t i; 1186 1187 var = ngx_array_push(&ccf->env); 1188 if (var == NULL) { 1189 return NGX_CONF_ERROR; 1190 } 1191 1192 value = cf->args->elts; 1193 *var = value[1]; 1194 1195 for (i = 0; i < value[1].len; i++) { 1196 1197 if (value[1].data[i] == '=') { 1198 1199 var->len = i; 1200 1201 return NGX_CONF_OK; 1202 } 1203 } 1204 1205 return NGX_CONF_OK; 1206 } 1207 1208 1209 static char * 1210 ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1211 { 1212 ngx_core_conf_t *ccf = conf; 1213 1214 ngx_str_t *value; 1215 ngx_uint_t n, minus; 1216 1217 if (ccf->priority != 0) { 1218 return "is duplicate"; 1219 } 1220 1221 value = cf->args->elts; 1222 1223 if (value[1].data[0] == '-') { 1224 n = 1; 1225 minus = 1; 1226 1227 } else if (value[1].data[0] == '+') { 1228 n = 1; 1229 minus = 0; 1230 1231 } else { 1232 n = 0; 1233 minus = 0; 1234 } 1235 1236 ccf->priority = ngx_atoi(&value[1].data[n], value[1].len - n); 1237 if (ccf->priority == NGX_ERROR) { 1238 return "invalid number"; 1239 } 1240 1241 if (minus) { 1242 ccf->priority = -ccf->priority; 1243 } 1244 1245 return NGX_CONF_OK; 1246 } 1247 1248 1249 static char * 1250 ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1251 { 1252 #if (NGX_HAVE_CPU_AFFINITY) 1253 ngx_core_conf_t *ccf = conf; 1254 1255 u_char ch; 1256 uint64_t *mask; 1257 ngx_str_t *value; 1258 ngx_uint_t i, n; 1259 1260 if (ccf->cpu_affinity) { 1261 return "is duplicate"; 1262 } 1263 1264 mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(uint64_t)); 1265 if (mask == NULL) { 1266 return NGX_CONF_ERROR; 1267 } 1268 1269 ccf->cpu_affinity_n = cf->args->nelts - 1; 1270 ccf->cpu_affinity = mask; 1271 1272 value = cf->args->elts; 1273 1274 for (n = 1; n < cf->args->nelts; n++) { 1275 1276 if (value[n].len > 64) { 1277 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1278 "\"worker_cpu_affinity\" supports up to 64 CPUs only"); 1279 return NGX_CONF_ERROR; 1280 } 1281 1282 mask[n - 1] = 0; 1283 1284 for (i = 0; i < value[n].len; i++) { 1285 1286 ch = value[n].data[i]; 1287 1288 if (ch == ' ') { 1289 continue; 1290 } 1291 1292 mask[n - 1] <<= 1; 1293 1294 if (ch == '0') { 1295 continue; 1296 } 1297 1298 if (ch == '1') { 1299 mask[n - 1] |= 1; 1300 continue; 1301 } 1302 1303 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1304 "invalid character \"%c\" in \"worker_cpu_affinity\"", 1305 ch); 1306 return NGX_CONF_ERROR; 1307 } 1308 } 1309 1310 #else 1311 1312 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 1313 "\"worker_cpu_affinity\" is not supported " 1314 "on this platform, ignored"); 1315 #endif 1316 1317 return NGX_CONF_OK; 1318 } 1319 1320 1321 uint64_t 1322 ngx_get_cpu_affinity(ngx_uint_t n) 1323 { 1324 ngx_core_conf_t *ccf; 1325 1326 ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, 1327 ngx_core_module); 1328 1329 if (ccf->cpu_affinity == NULL) { 1330 return 0; 1331 } 1332 1333 if (ccf->cpu_affinity_n > n) { 1334 return ccf->cpu_affinity[n]; 1335 } 1336 1337 return ccf->cpu_affinity[ccf->cpu_affinity_n - 1]; 1338 } 1339 1340 1341 static char * 1342 ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1343 { 1344 ngx_str_t *value; 1345 ngx_core_conf_t *ccf; 1346 1347 ccf = (ngx_core_conf_t *) conf; 1348 1349 if (ccf->worker_processes != NGX_CONF_UNSET) { 1350 return "is duplicate"; 1351 } 1352 1353 value = (ngx_str_t *) cf->args->elts; 1354 1355 if (ngx_strcmp(value[1].data, "auto") == 0) { 1356 ccf->worker_processes = ngx_ncpu; 1357 return NGX_CONF_OK; 1358 } 1359 1360 ccf->worker_processes = ngx_atoi(value[1].data, value[1].len); 1361 1362 if (ccf->worker_processes == NGX_ERROR) { 1363 return "invalid value"; 1364 } 1365 1366 return NGX_CONF_OK; 1367 }
Nginx的启动包括了很多的初始化和处理函数。这些函数相对来说,有一部分非常复杂,暂且从简单开始,从整体上对Ngixnd的启动有一个了解,方便日后的分析与学习。
主要函数:
//完成socket的继承
static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle);
//对参数选项进行处理 static ngx_int_t ngx_get_options(int argc, char *const *argv);
//初始化ngx_cycle内的部分内容 static ngx_int_t ngx_process_options(ngx_cycle_t *cycle);
//命令行参数保存到ngx_os_argv、ngx_argc以及ngx_argv全局的变量中 static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv);
//创建模块的配置信息 static void *ngx_core_module_create_conf(ngx_cycle_t *cycle);
//初始化配置信息 static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf); static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
//设置优先级 static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
//设置CPU亲和性 static char *ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
//设置worker进程 static char *ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
Nginx启动的主要流程
下图为Nginx的启动时函数的调用过程,其中大部分都是为了Nginx启动的初始化部分。从错误处理、参数设置、时间设置等方面进行初始化,并注册了我们需要的模块,最后根据信号选择单任务模式还是master-worker模式。
流程图:
初始化
主函数在开始对系统错误、参数、时间、系统变量、日志等进行了初始化。
//初始化系统中错误编号对应的含义 ngx_strerror_init(); //对参数选项进行处理 ngx_get_options(argc, argv); //时间初始化 ngx_time_init(); //重置pcre内存管理的接口 ngx_regex_init(); //日志初始化 ngx_log_init(ngx_prefix);
//创建内存池
ngx_create_pool(1024, log);
//保存变量
ngx_save_argv();
//初始化ngx_cycle的prefix, conf_prefix, conf_file, conf_param
ngx_process_options();
//初始化系统相关变量,如内存页面大小ngx_pagesize,ngx_cacheline_size,最大连接数ngx_max_sockets等
ngx_os_init();
//初始化CRC表(后续的CRC校验通过查表进行,效率高)
ngx_crc32_table_init();
主要工作
初始化完成后,需要先调用ngx_add_inherited_sockets函数继承socket,并储存在Listening数组中,在运行时候进行监听。之后就可以调用ngx_init_cycle来初始化ngx_cycle结构体,这个结构体用来存储所有的连接,具体如下:
struct ngx_cycle_s { void ****conf_ctx;//配置上下文数组(含所有模块) ngx_pool_t *pool;//内存池 ngx_log_t *log;//日志 ngx_log_t new_log; ngx_connection_t **files;//连接文件 ngx_connection_t *free_connections;//空闲连接 ngx_uint_t free_connection_n;//空闲连接数 ngx_queue_t reusable_connections_queue;////再利用连接队列 ngx_array_t listening;//监听数组 ngx_array_t paths;//路径数组 ngx_list_t open_files;//打开文件链表 ngx_list_t shared_memory;//共享内存链表 ngx_uint_t connection_n;//连接个数 ngx_uint_t files_n;//打开文件个数 ngx_connection_t *connections; ngx_event_t *read_events;//读事件 ngx_event_t *write_events;//写事件 ngx_cycle_t *old_cycle; ngx_str_t conf_file;//配置文件 ngx_str_t conf_param;//配置参数 ngx_str_t conf_prefix;//配置前缀 ngx_str_t prefix;//前缀 ngx_str_t lock_file;//锁文件 ngx_str_t hostname;
调用ngx_init_signals来注册信号。
//信号种类
#define NGX_PROCESS_SINGLE 0 #define NGX_PROCESS_MASTER 1 #define NGX_PROCESS_SIGNALLER 2 #define NGX_PROCESS_WORKER 3 #define NGX_PROCESS_HELPER 4
在进入处理之前,还要调用ngx_create_pidfile来记录进程id。最后,根据接收到的信号,来判断调用ngx_single_process_cycle还是ngx_master_process_cycle(master-worker模式)。
if (ngx_process == NGX_PROCESS_SINGLE) { ngx_single_process_cycle(cycle); } else { ngx_master_process_cycle(cycle); }
其中,守护进程函数为ngx_daemon,位于src/os/unix/Ngx_daemon.c
//daemon
ngx_int_t ngx_daemon(ngx_log_t *log) { int fd; switch (fork()) { case -1: ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed"); return NGX_ERROR; case 0: breakdefault: exit(0); } ngx_pid = ngx_getpid();//取得进程识别码 if (setsid() == -1) { //子进程将重新获得一个新的会话(session)id ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed"); return NGX_ERROR; } umask(0); fd = open("/dev/null", O_RDWR); if (fd == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "open(\"/dev/null\") failed"); return NGX_ERROR; } if (dup2(fd, STDIN_FILENO) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed"); return NGX_ERROR; } if (dup2(fd, STDOUT_FILENO) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed"); return NGX_ERROR; } #if 0 if (dup2(fd, STDERR_FILENO) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed"); return NGX_ERROR; } #endif if (fd > STDERR_FILENO) { if (close(fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed"); return NGX_ERROR; } } return NGX_OK; }
参考
http://blog.xiuwz.com/2011/11/29/nginx-pcre-conflict/
http://blog.csdn.net/liuhongxiangm/article/details/8107613
http://www.4os.org/index.php/2010/11/25/nginx%E5%90%AF%E5%8A%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E8%BF%87%E7%A8%8B%E8%BD%AC%E8%BD%BD/
http://blog.csdn.net/livelylittlefish/article/details/7243718
本文 由 cococo点点 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,请注明出处:
转载自:cococo点点 http://www.cnblogs.com/coder2012