您的位置:首页 > 编程语言 > PHP开发

php源码fpm分析

2017-03-05 13:23 495 查看
源码为php-7.1.2

在/sapi/fpm/fpm/fpm_main.c中的main方法。

其中最重要的有2点

第一:fcgi_fd = fpm_run(&max_requests);实现了fpm的进程控制。

php-fpm支持三种运行模式,分别为
static
ondemand
dynamic
,默认为
dynamic


static
: 静态模式,启动时分配固定的worker进程。

ondemand
: 按需分配,当收到用户请求时fork worker进程。

dynamic
: 动态模式,启动时分配固定的进程。伴随着请求数增加,在设定的浮动范围调整worker进程。

这三种模式各有千秋,大家可以根据不同的环境调整相应的配置。

php-fpm采用master/worker架构设计,前面简单地描述master和worker进程模块的功能,其中

master进程通过
fpm_event_loop
函数处理,其内部是一个死循环,负责事件的收集工作,

work进程处理用户进程

第二: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;
}
/* }}} */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: