源碼爲php-7.1.2php
在/sapi/fpm/fpm/fpm_main.c中的main方法。web
其中最重要的有2點apache
第一:fcgi_fd = fpm_run(&max_requests);實現了fpm的進程控制。windows
php-fpm支持三種運行模式,分別爲static
、ondemand
、dynamic
,默認爲dynamic
。
static
: 靜態模式,啓動時分配固定的worker進程。
ondemand
: 按需分配,當收到用戶請求時fork worker進程。
dynamic
: 動態模式,啓動時分配固定的進程。伴隨着請求數增長,在設定的浮動範圍調整worker進程。api
這三種模式各有千秋,你們能夠根據不一樣的環境調整相應的配置。架構
php-fpm採用master/worker架構設計,前面簡單地描述master和worker進程模塊的功能,其中app
master進程經過fpm_event_loop
函數處理,其內部是一個死循環,負責事件的收集工做,socket
work進程處理用戶進程ide
第二:php_execute_script執行php腳本,最終調用zend引擎,執行代碼函數
int main(int argc, char *argv[]) { int exit_status = FPM_EXIT_OK; int cgi = 0, c, use_extended_info = 0; zend_file_handle file_handle; /* temporary locals */ int orig_optind = php_optind; char *orig_optarg = php_optarg; int ini_entries_len = 0; /* end of temporary locals */ #ifdef ZTS void ***tsrm_ls; #endif int max_requests = 500; int requests = 0; int fcgi_fd = 0; fcgi_request *request; char *fpm_config = NULL; char *fpm_prefix = NULL; char *fpm_pid = NULL; int test_conf = 0; int force_daemon = -1; int force_stderr = 0; int php_information = 0; int php_allow_to_run_as_root = 0; #ifdef HAVE_SIGNAL_H #if defined(SIGPIPE) && defined(SIG_IGN) signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so that sockets created via fsockopen() don't kill PHP if the remote site closes it. in apache|apxs mode apache does that for us! thies@thieso.net 20000419 */ #endif #endif #ifdef ZTS tsrm_startup(1, 1, 0, NULL); tsrm_ls = ts_resource(0); #endif zend_signal_startup(); sapi_startup(&cgi_sapi_module); cgi_sapi_module.php_ini_path_override = NULL; cgi_sapi_module.php_ini_ignore_cwd = 1; #ifndef HAVE_ATTRIBUTE_WEAK fcgi_set_logger(fpm_fcgi_log); #endif fcgi_init(); #ifdef PHP_WIN32 _fmode = _O_BINARY; /* sets default for file streams to binary */ setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */ setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */ setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */ #endif while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) { switch (c) { case 'c': if (cgi_sapi_module.php_ini_path_override) { free(cgi_sapi_module.php_ini_path_override); } cgi_sapi_module.php_ini_path_override = strdup(php_optarg); break; case 'n': cgi_sapi_module.php_ini_ignore = 1; break; case 'd': { /* define ini entries on command line */ int len = strlen(php_optarg); char *val; if ((val = strchr(php_optarg, '='))) { val++; if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') { cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\"\"\n\0")); memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, (val - php_optarg)); ini_entries_len += (val - php_optarg); memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"", 1); ini_entries_len++; memcpy(cgi_sapi_module.ini_entries + ini_entries_len, val, len - (val - php_optarg)); ini_entries_len += len - (val - php_optarg); memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0")); ini_entries_len += sizeof("\n\0\"") - 2; } else { cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\n\0")); memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len); memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0")); ini_entries_len += len + sizeof("\n\0") - 2; } } else { cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("=1\n\0")); memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len); memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0")); ini_entries_len += len + sizeof("=1\n\0") - 2; } break; } case 'y': fpm_config = php_optarg; break; case 'p': fpm_prefix = php_optarg; break; case 'g': fpm_pid = php_optarg; break; case 'e': /* enable extended info output */ use_extended_info = 1; break; case 't': test_conf++; break; case 'm': /* list compiled in modules */ cgi_sapi_module.startup(&cgi_sapi_module); php_output_activate(); SG(headers_sent) = 1; php_printf("[PHP Modules]\n"); print_modules(); php_printf("\n[Zend Modules]\n"); print_extensions(); php_printf("\n"); php_output_end_all(); php_output_deactivate(); fcgi_shutdown(); exit_status = FPM_EXIT_OK; goto out; case 'i': /* php info & quit */ php_information = 1; break; case 'R': /* allow to run as root */ php_allow_to_run_as_root = 1; break; case 'D': /* daemonize */ force_daemon = 1; break; case 'F': /* nodaemonize */ force_daemon = 0; break; case 'O': /* force stderr even on non tty */ force_stderr = 1; break; default: case 'h': case '?': cgi_sapi_module.startup(&cgi_sapi_module); php_output_activate(); SG(headers_sent) = 1; php_cgi_usage(argv[0]); php_output_end_all(); php_output_deactivate(); fcgi_shutdown(); exit_status = (c == 'h') ? FPM_EXIT_OK : FPM_EXIT_USAGE; goto out; case 'v': /* show php version & quit */ cgi_sapi_module.startup(&cgi_sapi_module); if (php_request_startup() == FAILURE) { SG(server_context) = NULL; php_module_shutdown(); return FPM_EXIT_SOFTWARE; } SG(headers_sent) = 1; SG(request_info).no_headers = 1; #if ZEND_DEBUG php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2017 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #else php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2017 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #endif php_request_shutdown((void *) 0); fcgi_shutdown(); exit_status = FPM_EXIT_OK; goto out; } } if (php_information) { cgi_sapi_module.phpinfo_as_text = 1; cgi_sapi_module.startup(&cgi_sapi_module); if (php_request_startup() == FAILURE) { SG(server_context) = NULL; php_module_shutdown(); return FPM_EXIT_SOFTWARE; } SG(headers_sent) = 1; SG(request_info).no_headers = 1; php_print_info(0xFFFFFFFF); php_request_shutdown((void *) 0); fcgi_shutdown(); exit_status = FPM_EXIT_OK; goto out; } /* No other args are permitted here as there is no interactive mode */ if (argc != php_optind) { cgi_sapi_module.startup(&cgi_sapi_module); php_output_activate(); SG(headers_sent) = 1; php_cgi_usage(argv[0]); php_output_end_all(); php_output_deactivate(); fcgi_shutdown(); exit_status = FPM_EXIT_USAGE; goto out; } php_optind = orig_optind; php_optarg = orig_optarg; #ifdef ZTS SG(request_info).path_translated = NULL; #endif cgi_sapi_module.additional_functions = NULL; cgi_sapi_module.executable_location = argv[0]; /* startup after we get the above ini override se we get things right */ if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) { #ifdef ZTS tsrm_shutdown(); #endif return FPM_EXIT_SOFTWARE; } if (use_extended_info) { CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; } /* check force_cgi after startup, so we have proper output */ if (cgi && CGIG(force_redirect)) { /* Apache will generate REDIRECT_STATUS, * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS. * redirect.so and installation instructions available from * http://www.koehntopp.de/php. * -- kk@netuse.de */ if (!getenv("REDIRECT_STATUS") && !getenv ("HTTP_REDIRECT_STATUS") && /* this is to allow a different env var to be configured * in case some server does something different than above */ (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env))) ) { zend_try { SG(sapi_headers).http_response_code = 400; PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\ <p>This PHP CGI binary was compiled with force-cgi-redirect enabled. This\n\ means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\ set, e.g. via an Apache Action directive.</p>\n\ <p>For more information as to <i>why</i> this behaviour exists, see the <a href=\"http://php.net/security.cgi-bin\">\ manual page for CGI security</a>.</p>\n\ <p>For more information about changing this behaviour or re-enabling this webserver,\n\ consult the installation file that came with this distribution, or visit \n\ <a href=\"http://php.net/install.windows\">the manual page</a>.</p>\n"); } zend_catch { } zend_end_try(); #if defined(ZTS) && !defined(PHP_DEBUG) /* XXX we're crashing here in msvc6 debug builds at * php_message_handler_for_zend:839 because * SG(request_info).path_translated is an invalid pointer. * It still happens even though I set it to null, so something * weird is going on. */ tsrm_shutdown(); #endif return FPM_EXIT_SOFTWARE; } } if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)) { if (fpm_globals.send_config_pipe[1]) { int writeval = 0; zlog(ZLOG_DEBUG, "Sending \"0\" (error) to parent via fd=%d", fpm_globals.send_config_pipe[1]); zend_quiet_write(fpm_globals.send_config_pipe[1], &writeval, sizeof(writeval)); close(fpm_globals.send_config_pipe[1]); } return FPM_EXIT_CONFIG; } if (fpm_globals.send_config_pipe[1]) { int writeval = 1; zlog(ZLOG_DEBUG, "Sending \"1\" (OK) to parent via fd=%d", fpm_globals.send_config_pipe[1]); zend_quiet_write(fpm_globals.send_config_pipe[1], &writeval, sizeof(writeval)); close(fpm_globals.send_config_pipe[1]); } fpm_is_running = 1; fcgi_fd = fpm_run(&max_requests); parent = 0; /* onced forked tell zlog to also send messages through sapi_cgi_log_fastcgi() */ zlog_set_external_logger(sapi_cgi_log_fastcgi); /* make php call us to get _ENV vars */ php_php_import_environment_variables = php_import_environment_variables; php_import_environment_variables = cgi_php_import_environment_variables; /* library is already initialized, now init our request */ request = fpm_init_request(fcgi_fd); zend_first_try { while (EXPECTED(fcgi_accept_request(request) >= 0)) { char *primary_script = NULL; request_body_fd = -1; SG(server_context) = (void *) request; init_request_info(); fpm_request_info(); /* request startup only after we've done all we can to * get path_translated */ if (UNEXPECTED(php_request_startup() == FAILURE)) { fcgi_finish_request(request, 1); SG(server_context) = NULL; php_module_shutdown(); return FPM_EXIT_SOFTWARE; } /* check if request_method has been sent. * if not, it's certainly not an HTTP over fcgi request */ if (UNEXPECTED(!SG(request_info).request_method)) { goto fastcgi_request_done; } if (UNEXPECTED(fpm_status_handle_request())) { goto fastcgi_request_done; } /* If path_translated is NULL, terminate here with a 404 */ if (UNEXPECTED(!SG(request_info).path_translated)) { zend_try { zlog(ZLOG_DEBUG, "Primary script unknown"); SG(sapi_headers).http_response_code = 404; PUTS("File not found.\n"); } zend_catch { } zend_end_try(); goto fastcgi_request_done; } if (UNEXPECTED(fpm_php_limit_extensions(SG(request_info).path_translated))) { SG(sapi_headers).http_response_code = 403; PUTS("Access denied.\n"); goto fastcgi_request_done; } /* * have to duplicate SG(request_info).path_translated to be able to log errrors * php_fopen_primary_script seems to delete SG(request_info).path_translated on failure */ primary_script = estrdup(SG(request_info).path_translated); /* path_translated exists, we can continue ! */ if (UNEXPECTED(php_fopen_primary_script(&file_handle) == FAILURE)) { zend_try { zlog(ZLOG_ERROR, "Unable to open primary script: %s (%s)", primary_script, strerror(errno)); if (errno == EACCES) { SG(sapi_headers).http_response_code = 403; PUTS("Access denied.\n"); } else { SG(sapi_headers).http_response_code = 404; PUTS("No input file specified.\n"); } } zend_catch { } zend_end_try(); /* we want to serve more requests if this is fastcgi * so cleanup and continue, request shutdown is * handled later */ goto fastcgi_request_done; } fpm_request_executing(); php_execute_script(&file_handle); fastcgi_request_done: if (EXPECTED(primary_script)) { efree(primary_script); } if (UNEXPECTED(request_body_fd != -1)) { close(request_body_fd); } request_body_fd = -2; if (UNEXPECTED(EG(exit_status) == 255)) { if (CGIG(error_header) && *CGIG(error_header)) { sapi_header_line ctr = {0}; ctr.line = CGIG(error_header); ctr.line_len = strlen(CGIG(error_header)); sapi_header_op(SAPI_HEADER_REPLACE, &ctr); } } fpm_request_end(); fpm_log_write(NULL); efree(SG(request_info).path_translated); SG(request_info).path_translated = NULL; php_request_shutdown((void *) 0); requests++; if (UNEXPECTED(max_requests && (requests == max_requests))) { fcgi_finish_request(request, 1); break; } /* end of fastcgi loop */ } fcgi_destroy_request(request); fcgi_shutdown(); if (cgi_sapi_module.php_ini_path_override) { free(cgi_sapi_module.php_ini_path_override); } if (cgi_sapi_module.ini_entries) { free(cgi_sapi_module.ini_entries); } } zend_catch { exit_status = FPM_EXIT_SOFTWARE; } zend_end_try(); out: SG(server_context) = NULL; php_module_shutdown(); if (parent) { sapi_shutdown(); } #ifdef ZTS tsrm_shutdown(); #endif #if defined(PHP_WIN32) && ZEND_DEBUG && 0 _CrtDumpMemoryLeaks(); #endif return exit_status; } /* }}} */