diff options
| author | Ondřej Surý <ondrej@sury.org> | 2012-01-11 15:43:42 +0100 |
|---|---|---|
| committer | Ondřej Surý <ondrej@sury.org> | 2012-01-11 15:43:42 +0100 |
| commit | 8f1428d29ef91d74b4d272af171675f2971eb15b (patch) | |
| tree | a1f4f4d7dc5bfe8096806dd5c5266634e19fa07a /sapi | |
| parent | c6e4182351e0173fe58de141e143aac2eacf5efe (diff) | |
| download | php-upstream/5.3.9.tar.gz | |
Imported Upstream version 5.3.9upstream/5.3.9
Diffstat (limited to 'sapi')
100 files changed, 3857 insertions, 734 deletions
diff --git a/sapi/aolserver/aolserver.c b/sapi/aolserver/aolserver.c index fda7364c7..53010e7f5 100644 --- a/sapi/aolserver/aolserver.c +++ b/sapi/aolserver/aolserver.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -22,7 +22,7 @@ * - CGI/1.1 conformance */ -/* $Id: aolserver.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: aolserver.c 321634 2012-01-01 13:15:04Z felipe $ */ /* conflict between PHP and AOLserver headers */ #define Debug php_Debug @@ -205,7 +205,7 @@ static void php_info_aolserver(ZEND_MODULE_INFO_FUNC_ARGS) int i; php_info_print_table_start(); - php_info_print_table_row(2, "SAPI module version", "$Id: aolserver.c 306939 2011-01-01 02:19:59Z felipe $"); + php_info_print_table_row(2, "SAPI module version", "$Id: aolserver.c 321634 2012-01-01 13:15:04Z felipe $"); php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); diff --git a/sapi/apache/libpre.c b/sapi/apache/libpre.c index 033ea5461..2361db9ab 100644 --- a/sapi/apache/libpre.c +++ b/sapi/apache/libpre.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: libpre.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: libpre.c 321634 2012-01-01 13:15:04Z felipe $ */ #ifdef NETWARE diff --git a/sapi/apache/mod_php5.c b/sapi/apache/mod_php5.c index ebcd69f7f..76139575b 100644 --- a/sapi/apache/mod_php5.c +++ b/sapi/apache/mod_php5.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ | PHP 4.0 patches by Zeev Suraski <zeev@zend.com> | +----------------------------------------------------------------------+ */ -/* $Id: mod_php5.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: mod_php5.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_apache_http.h" #include "http_conf_globals.h" @@ -533,7 +533,7 @@ static void init_request_info(TSRMLS_D) SG(request_info).request_uri = r->uri; SG(request_info).request_method = (char *)r->method; SG(request_info).content_type = (char *) table_get(r->subprocess_env, "CONTENT_TYPE"); - SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + SG(request_info).content_length = (content_length ? atol(content_length) : 0); SG(sapi_headers).http_response_code = r->status; SG(request_info).proto_num = r->proto_num; diff --git a/sapi/apache/mod_php5.h b/sapi/apache/mod_php5.h index 1360731f9..df9dd9dbc 100644 --- a/sapi/apache/mod_php5.h +++ b/sapi/apache/mod_php5.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -15,7 +15,7 @@ | Author: Rasmus Lerdorf <rasmus@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: mod_php5.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: mod_php5.h 321634 2012-01-01 13:15:04Z felipe $ */ #ifndef MOD_PHP5_H #define MOD_PHP5_H diff --git a/sapi/apache/php_apache.c b/sapi/apache/php_apache.c index 0f73b848c..d171d56d4 100644 --- a/sapi/apache/php_apache.c +++ b/sapi/apache/php_apache.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ | David Sklar <sklar@student.net> | +----------------------------------------------------------------------+ */ -/* $Id: php_apache.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_apache.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_apache_http.h" diff --git a/sapi/apache/php_apache_http.h b/sapi/apache/php_apache_http.h index 693d1b721..aead028db 100644 --- a/sapi/apache/php_apache_http.h +++ b/sapi/apache/php_apache_http.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_apache_http.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_apache_http.h 321634 2012-01-01 13:15:04Z felipe $ */ #define NO_REGEX_EXTRA_H diff --git a/sapi/apache/sapi_apache.c b/sapi/apache/sapi_apache.c index 13827d648..9b9fa0a6f 100644 --- a/sapi/apache/sapi_apache.c +++ b/sapi/apache/sapi_apache.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -19,7 +19,7 @@ | Stig Bakken <ssb@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: sapi_apache.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: sapi_apache.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_apache_http.h" diff --git a/sapi/apache2filter/apache_config.c b/sapi/apache2filter/apache_config.c index 3b53f010d..301e48058 100644 --- a/sapi/apache2filter/apache_config.c +++ b/sapi/apache2filter/apache_config.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: apache_config.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: apache_config.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS diff --git a/sapi/apache2filter/php_apache.h b/sapi/apache2filter/php_apache.h index 72eaa3f17..ebbed1d5c 100644 --- a/sapi/apache2filter/php_apache.h +++ b/sapi/apache2filter/php_apache.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_apache.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_apache.h 321634 2012-01-01 13:15:04Z felipe $ */ #ifndef PHP_APACHE_H #define PHP_APACHE_H diff --git a/sapi/apache2filter/php_functions.c b/sapi/apache2filter/php_functions.c index 8b5ba8331..cbb0e4cf8 100644 --- a/sapi/apache2filter/php_functions.c +++ b/sapi/apache2filter/php_functions.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_functions.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_functions.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS diff --git a/sapi/apache2filter/sapi_apache2.c b/sapi/apache2filter/sapi_apache2.c index f2c7a87d8..6597057f3 100644 --- a/sapi/apache2filter/sapi_apache2.c +++ b/sapi/apache2filter/sapi_apache2.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: sapi_apache2.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: sapi_apache2.c 321634 2012-01-01 13:15:04Z felipe $ */ #include <fcntl.h> @@ -420,7 +420,7 @@ static void php_apache_request_ctor(ap_filter_t *f, php_struct *ctx TSRMLS_DC) efree(content_type); content_length = (char *) apr_table_get(f->r->headers_in, "Content-Length"); - SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + SG(request_info).content_length = (content_length ? atol(content_length) : 0); apr_table_unset(f->r->headers_out, "Content-Length"); apr_table_unset(f->r->headers_out, "Last-Modified"); diff --git a/sapi/apache2handler/apache_config.c b/sapi/apache2handler/apache_config.c index c7eafeb96..2d221fe87 100644 --- a/sapi/apache2handler/apache_config.c +++ b/sapi/apache2handler/apache_config.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: apache_config.c 311342 2011-05-23 01:47:06Z felipe $ */ +/* $Id: apache_config.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS diff --git a/sapi/apache2handler/mod_php5.c b/sapi/apache2handler/mod_php5.c index 56bfdad35..9884fc66b 100644 --- a/sapi/apache2handler/mod_php5.c +++ b/sapi/apache2handler/mod_php5.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mod_php5.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: mod_php5.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS diff --git a/sapi/apache2handler/php_apache.h b/sapi/apache2handler/php_apache.h index 2ee8bd896..292919327 100644 --- a/sapi/apache2handler/php_apache.h +++ b/sapi/apache2handler/php_apache.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_apache.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_apache.h 321634 2012-01-01 13:15:04Z felipe $ */ #ifndef PHP_APACHE_H #define PHP_APACHE_H diff --git a/sapi/apache2handler/php_functions.c b/sapi/apache2handler/php_functions.c index b7cc64054..ed9a03165 100644 --- a/sapi/apache2handler/php_functions.c +++ b/sapi/apache2handler/php_functions.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_functions.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_functions.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 18f21247a..d373adb50 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: sapi_apache2.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: sapi_apache2.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS @@ -484,7 +484,7 @@ static int php_apache_request_ctor(request_rec *r, php_struct *ctx TSRMLS_DC) r->no_local_copy = 1; content_length = (char *) apr_table_get(r->headers_in, "Content-Length"); - SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + SG(request_info).content_length = (content_length ? atol(content_length) : 0); apr_table_unset(r->headers_out, "Content-Length"); apr_table_unset(r->headers_out, "Last-Modified"); diff --git a/sapi/apache_hooks/mod_php5.c b/sapi/apache_hooks/mod_php5.c index 79a733b4b..db68e5c9b 100644 --- a/sapi/apache_hooks/mod_php5.c +++ b/sapi/apache_hooks/mod_php5.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ | PHP 4.0 patches by Zeev Suraski <zeev@zend.com> | +----------------------------------------------------------------------+ */ -/* $Id: mod_php5.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: mod_php5.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_apache_http.h" @@ -587,7 +587,7 @@ static void init_request_info(TSRMLS_D) SG(request_info).request_method = (char *)r->method; SG(request_info).proto_num = r->proto_num; SG(request_info).content_type = (char *) table_get(r->subprocess_env, "CONTENT_TYPE"); - SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + SG(request_info).content_length = (content_length ? atol(content_length) : 0); SG(sapi_headers).http_response_code = r->status; if (r->headers_in) { diff --git a/sapi/apache_hooks/mod_php5.h b/sapi/apache_hooks/mod_php5.h index 08ec4eb41..a665a5083 100644 --- a/sapi/apache_hooks/mod_php5.h +++ b/sapi/apache_hooks/mod_php5.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -15,7 +15,7 @@ | Author: Rasmus Lerdorf <rasmus@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: mod_php5.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: mod_php5.h 321634 2012-01-01 13:15:04Z felipe $ */ #ifndef MOD_PHP5_H #define MOD_PHP5_H diff --git a/sapi/apache_hooks/php_apache.c b/sapi/apache_hooks/php_apache.c index 8a4920920..bfcc629f0 100644 --- a/sapi/apache_hooks/php_apache.c +++ b/sapi/apache_hooks/php_apache.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ | David Sklar <sklar@student.net> | +----------------------------------------------------------------------+ */ -/* $Id: php_apache.c 314352 2011-08-06 01:22:27Z felipe $ */ +/* $Id: php_apache.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_apache_http.h" diff --git a/sapi/apache_hooks/sapi_apache.c b/sapi/apache_hooks/sapi_apache.c index f1b948be9..568f10c4a 100644 --- a/sapi/apache_hooks/sapi_apache.c +++ b/sapi/apache_hooks/sapi_apache.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -19,7 +19,7 @@ | Stig Bakken <ssb@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: sapi_apache.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: sapi_apache.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_apache_http.h" diff --git a/sapi/caudium/caudium.c b/sapi/caudium/caudium.c index e0c4847f3..51d0c3087 100644 --- a/sapi/caudium/caudium.c +++ b/sapi/caudium/caudium.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: caudium.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: caudium.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #ifdef HAVE_CAUDIUM @@ -444,7 +444,7 @@ static void php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS) { /* char buf[512]; */ php_info_print_table_start(); - php_info_print_table_row(2, "SAPI module version", "$Id: caudium.c 306939 2011-01-01 02:19:59Z felipe $"); + php_info_print_table_row(2, "SAPI module version", "$Id: caudium.c 321634 2012-01-01 13:15:04Z felipe $"); /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 590419ee8..083c6e353 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -21,7 +21,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: cgi_main.c 314773 2011-08-11 06:38:42Z dmitry $ */ +/* $Id: cgi_main.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #include "php_globals.h" @@ -1353,7 +1353,7 @@ static void init_request_info(TSRMLS_D) /* FIXME - Work out proto_num here */ SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC); SG(request_info).content_type = (content_type ? content_type : "" ); - SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + SG(request_info).content_length = (content_length ? atol(content_length) : 0); /* The CGI RFC allows servers to pass on unvalidated Authorization data */ auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC); @@ -1933,9 +1933,9 @@ consult the installation file that came with this distribution, or visit \n\ SG(request_info).no_headers = 1; } #if ZEND_DEBUG - php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2011 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2012 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-2011 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); #endif php_request_shutdown((void *) 0); fcgi_shutdown(); diff --git a/sapi/cgi/fastcgi.c b/sapi/cgi/fastcgi.c index c6f96f3e2..66628f60c 100644 --- a/sapi/cgi/fastcgi.c +++ b/sapi/cgi/fastcgi.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: fastcgi.c 307579 2011-01-19 08:38:25Z dmitry $ */ +/* $Id: fastcgi.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #include "fastcgi.h" diff --git a/sapi/cgi/fastcgi.h b/sapi/cgi/fastcgi.h index 226b68f3e..9b42f07a0 100644 --- a/sapi/cgi/fastcgi.h +++ b/sapi/cgi/fastcgi.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: fastcgi.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: fastcgi.h 321634 2012-01-01 13:15:04Z felipe $ */ /* FastCGI protocol */ diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index c80d46490..3fbce7476 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -20,7 +20,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_cli.c 314468 2011-08-08 07:12:12Z laruence $ */ +/* $Id: php_cli.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #include "php_globals.h" @@ -826,7 +826,7 @@ int main(int argc, char *argv[]) } request_started = 1; - php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2011 The PHP Group\n%s", + php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, #if ZEND_DEBUG && defined(HAVE_GCOV) "(DEBUG GCOV)", diff --git a/sapi/cli/php_cli_readline.c b/sapi/cli/php_cli_readline.c index 4b601ee55..888f4b60b 100644 --- a/sapi/cli/php_cli_readline.c +++ b/sapi/cli/php_cli_readline.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_cli_readline.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_cli_readline.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" diff --git a/sapi/cli/php_cli_readline.h b/sapi/cli/php_cli_readline.h index 93d869603..d62bb7d50 100644 --- a/sapi/cli/php_cli_readline.h +++ b/sapi/cli/php_cli_readline.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_cli_readline.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_cli_readline.h 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" diff --git a/sapi/cli/tests/016.phpt b/sapi/cli/tests/016.phpt index adde106df..9c28d15a3 100644 --- a/sapi/cli/tests/016.phpt +++ b/sapi/cli/tests/016.phpt @@ -65,25 +65,37 @@ Snippet no. 1: -------------- Interactive shell -php > Hello world -php > +php > echo 'Hello world'; +Hello world +php > exit + -------------- Snippet no. 2: -------------- Interactive shell -php > php ' php ' multine +php > echo 'multine +php ' single +php ' quote'; +multine single quote -php > +php > exit + -------------- Snippet no. 3: -------------- Interactive shell -php > <<< > <<< > <<< > <<< > <<< > Here +php > echo <<<HEREDOC +<<< > Here +<<< > comes +<<< > the +<<< > doc +<<< > HEREDOC; +Here comes the doc @@ -94,7 +106,11 @@ Snippet no. 4: -------------- Interactive shell -php > php { php { php > Done +php > if (0) { +php { echo "I'm not there"; +php { } +php > echo "Done"; +Done php > -------------- @@ -102,7 +118,11 @@ Snippet no. 5: -------------- Interactive shell -php > php { php { php > I was called! +php > function a_function_with_some_name() { +php { echo "I was called!"; +php { } +php > a_function_with_some_name(); +I was called! php > Done diff --git a/sapi/cli/tests/021.phpt b/sapi/cli/tests/021.phpt index a4442b0e0..2ddd68890 100644 --- a/sapi/cli/tests/021.phpt +++ b/sapi/cli/tests/021.phpt @@ -6,6 +6,10 @@ include 'skipif.inc'; if (substr(PHP_OS, 0, 3) == 'WIN') { die ("skip not for Windows"); } + +if (strlen("#!".getenv('TEST_PHP_EXECUTABLE')) > 127) { + die ("skip shebang is too long, see http://www.in-ulm.de/~mascheck/various/shebang/#results"); +} ?> --FILE-- <?php diff --git a/sapi/cli/tests/022.phpt b/sapi/cli/tests/022.phpt index eabb8bdf8..0110220be 100644 --- a/sapi/cli/tests/022.phpt +++ b/sapi/cli/tests/022.phpt @@ -8,7 +8,7 @@ if (substr(PHP_OS, 0, 3) == "WIN") die("skip non windows test"); --FILE-- <?php $php = getenv("TEST_PHP_EXECUTABLE"); -$socket_file = dirname(__FILE__) . '/' . pathinfo(__FILE__, PATHINFO_FILENAME) . '.sock'; +$socket_file = tempnam(sys_get_temp_dir(), pathinfo(__FILE__, PATHINFO_FILENAME) . '.sock'); $test_file = dirname(__FILE__) . '/' . pathinfo(__FILE__, PATHINFO_FILENAME) . '.inc'; if (file_exists($socket_file)) { unlink($socket_file); diff --git a/sapi/continuity/capi.c b/sapi/continuity/capi.c index 720727bb7..4253cc28f 100644 --- a/sapi/continuity/capi.c +++ b/sapi/continuity/capi.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -110,7 +110,7 @@ PHP_MSHUTDOWN_FUNCTION(continuity) PHP_MINFO_FUNCTION(continuity) { php_info_print_table_start(); - php_info_print_table_row(2, "Continuity Module Revision", "$Revision: 306939 $"); + php_info_print_table_row(2, "Continuity Module Revision", "$Revision: 321634 $"); php_info_print_table_row(2, "Server Version", conFget_build()); #ifdef CONTINUITY_CDPEXT php_info_print_table_row(2,"CDP Extensions", "enabled"); diff --git a/sapi/embed/php_embed.c b/sapi/embed/php_embed.c index 563d3e10c..a412d0515 100644 --- a/sapi/embed/php_embed.c +++ b/sapi/embed/php_embed.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -15,7 +15,7 @@ | Author: Edin Kadribasic <edink@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: php_embed.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_embed.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php_embed.h" #include "ext/standard/php_standard.h" diff --git a/sapi/embed/php_embed.h b/sapi/embed/php_embed.h index c5e731d5e..9cd21fb95 100644 --- a/sapi/embed/php_embed.h +++ b/sapi/embed/php_embed.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -15,7 +15,7 @@ | Author: Edin Kadribasic <edink@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: php_embed.h 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php_embed.h 321634 2012-01-01 13:15:04Z felipe $ */ #ifndef _PHP_EMBED_H_ #define _PHP_EMBED_H_ diff --git a/sapi/fpm/Makefile.frag b/sapi/fpm/Makefile.frag index 0859ef10c..c5cea7e52 100644 --- a/sapi/fpm/Makefile.frag +++ b/sapi/fpm/Makefile.frag @@ -2,6 +2,7 @@ fpm: $(SAPI_FPM_PATH) $(builddir)/fpm: @mkdir -p $(builddir)/fpm + @mkdir -p $(builddir)/fpm/events $(SAPI_FPM_PATH): $(builddir)/fpm $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(SAPI_EXTRA_DEPS) $(BUILD_FPM) @@ -26,3 +27,6 @@ install-fpm: install-sapi @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man8 @$(INSTALL_DATA) sapi/fpm/php-fpm.8 $(INSTALL_ROOT)$(mandir)/man8/php-fpm$(program_suffix).8 + @echo "Installing PHP FPM status page: $(INSTALL_ROOT)$(datadir)/fpm/" + @$(mkinstalldirs) $(INSTALL_ROOT)$(datadir)/fpm + @$(INSTALL_DATA) sapi/fpm/status.html $(INSTALL_ROOT)$(datadir)/fpm/status.html diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index 1105ec8d2..953fa1f7b 100644 --- a/sapi/fpm/config.m4 +++ b/sapi/fpm/config.m4 @@ -366,6 +366,171 @@ AC_DEFUN([AC_FPM_TIMES], ]) dnl }}} +AC_DEFUN([AC_FPM_KQUEUE], +[ + AC_MSG_CHECKING([for kqueue]) + + AC_TRY_COMPILE( + [ + #include <sys/types.h> + #include <sys/event.h> + #include <sys/time.h> + ], [ + int kfd; + struct kevent k; + kfd = kqueue(); + /* 0 -> STDIN_FILENO */ + EV_SET(&k, 0, EVFILT_READ , EV_ADD | EV_CLEAR, 0, 0, NULL); + ], [ + AC_DEFINE([HAVE_KQUEUE], 1, [do we have kqueue?]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) +]) +dnl }}} + +AC_DEFUN([AC_FPM_PORT], +[ + AC_MSG_CHECKING([for port framework]) + + AC_TRY_COMPILE( + [ + #include <port.h> + ], [ + int port; + + port = port_create(); + if (port < 0) { + return 1; + } + ], [ + AC_DEFINE([HAVE_PORT], 1, [do we have port framework?]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) +]) +dnl }}} + +AC_DEFUN([AC_FPM_DEVPOLL], +[ + AC_MSG_CHECKING([for /dev/poll]) + + AC_TRY_COMPILE( + [ + #include <stdio.h> + #include <sys/devpoll.h> + ], [ + int n, dp; + struct dvpoll dvp; + dp = 0; + dvp.dp_fds = NULL; + dvp.dp_nfds = 0; + dvp.dp_timeout = 0; + n = ioctl(dp, DP_POLL, &dvp) + ], [ + AC_DEFINE([HAVE_DEVPOLL], 1, [do we have /dev/poll?]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) +]) +dnl }}} + +AC_DEFUN([AC_FPM_EPOLL], +[ + AC_MSG_CHECKING([for epoll]) + + AC_TRY_COMPILE( + [ + #include <sys/epoll.h> + ], [ + int epollfd; + struct epoll_event e; + + epollfd = epoll_create(1); + if (epollfd < 0) { + return 1; + } + + e.events = EPOLLIN | EPOLLET; + e.data.fd = 0; + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, 0, &e) == -1) { + return 1; + } + + e.events = 0; + if (epoll_wait(epollfd, &e, 1, 1) < 0) { + return 1; + } + ], [ + AC_DEFINE([HAVE_EPOLL], 1, [do we have epoll?]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) +]) +dnl }}} + +AC_DEFUN([AC_FPM_POLL], +[ + AC_MSG_CHECKING([for poll]) + + AC_TRY_COMPILE( + [ + #include <poll.h> + ], [ + struct pollfd fds[2]; + + fds[0].fd = 0; + fds[0].events = POLLIN; + + fds[1].fd = 0; + fds[1].events = POLLIN; + + poll(fds, 2, 1); + ], [ + AC_DEFINE([HAVE_POLL], 1, [do we have poll?]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) +]) +dnl }}} + +AC_DEFUN([AC_FPM_SELECT], +[ + AC_MSG_CHECKING([for select]) + + AC_TRY_COMPILE( + [ + /* According to POSIX.1-2001 */ + #include <sys/select.h> + + /* According to earlier standards */ + #include <sys/time.h> + #include <sys/types.h> + #include <unistd.h> + ], [ + fd_set fds; + struct timeval t; + t.tv_sec = 0; + t.tv_usec = 42; + FD_ZERO(&fds); + /* 0 -> STDIN_FILENO */ + FD_SET(0, &fds); + select(FD_SETSIZE, &fds, NULL, NULL, &t); + ], [ + AC_DEFINE([HAVE_SELECT], 1, [do we have select?]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) +]) +dnl }}} + AC_MSG_CHECKING(for FPM build) if test "$PHP_FPM" != "no"; then @@ -379,6 +544,12 @@ if test "$PHP_FPM" != "no"; then AC_FPM_LQ AC_FPM_SYSCONF AC_FPM_TIMES + AC_FPM_KQUEUE + AC_FPM_PORT + AC_FPM_DEVPOLL + AC_FPM_EPOLL + AC_FPM_POLL + AC_FPM_SELECT PHP_ARG_WITH(fpm-user,, [ --with-fpm-user[=USER] Set the user for php-fpm to run as. (default: nobody)], nobody, no) @@ -411,7 +582,7 @@ if test "$PHP_FPM" != "no"; then AC_DEFINE_UNQUOTED(PHP_FPM_USER, "$php_fpm_user", [fpm user name]) AC_DEFINE_UNQUOTED(PHP_FPM_GROUP, "$php_fpm_group", [fpm group name]) - PHP_OUTPUT(sapi/fpm/php-fpm.conf sapi/fpm/init.d.php-fpm sapi/fpm/php-fpm.8) + PHP_OUTPUT(sapi/fpm/php-fpm.conf sapi/fpm/init.d.php-fpm sapi/fpm/php-fpm.8 sapi/fpm/status.html) PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/fpm/Makefile.frag], [$abs_srcdir/sapi/fpm], [sapi/fpm]) SAPI_FPM_PATH=sapi/fpm/php-fpm @@ -447,6 +618,12 @@ if test "$PHP_FPM" != "no"; then fpm/fpm_unix.c \ fpm/fpm_worker_pool.c \ fpm/zlog.c \ + fpm/events/select.c \ + fpm/events/poll.c \ + fpm/events/epoll.c \ + fpm/events/kqueue.c \ + fpm/events/devpoll.c \ + fpm/events/port.c \ " PHP_SELECT_SAPI(fpm, program, $PHP_FPM_FILES $PHP_FPM_TRACE_FILES, $PHP_FPM_CFLAGS, '$(SAPI_FPM_PATH)') diff --git a/sapi/fpm/fpm/events/devpoll.c b/sapi/fpm/fpm/events/devpoll.c new file mode 100644 index 000000000..eec7e5e13 --- /dev/null +++ b/sapi/fpm/fpm/events/devpoll.c @@ -0,0 +1,248 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "../fpm_config.h" +#include "../fpm_events.h" +#include "../fpm.h" +#include "../zlog.h" + +#if HAVE_DEVPOLL + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <poll.h> +#include <sys/devpoll.h> +#include <errno.h> + +static int fpm_event_devpoll_init(int max); +static int fpm_event_devpoll_clean(); +static int fpm_event_devpoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout); +static int fpm_event_devpoll_add(struct fpm_event_s *ev); +static int fpm_event_devpoll_remove(struct fpm_event_s *ev); + +static struct fpm_event_module_s devpoll_module = { + .name = "/dev/poll", + .support_edge_trigger = 0, + .init = fpm_event_devpoll_init, + .clean = fpm_event_devpoll_clean, + .wait = fpm_event_devpoll_wait, + .add = fpm_event_devpoll_add, + .remove = fpm_event_devpoll_remove, +}; + +int dpfd = -1; +static struct pollfd *pollfds = NULL; +static struct pollfd *active_pollfds = NULL; +static int npollfds = 0; + +#endif /* HAVE_DEVPOLL */ + +struct fpm_event_module_s *fpm_event_devpoll_module() /* {{{ */ +{ +#if HAVE_DEVPOLL + return &devpoll_module; +#else + return NULL; +#endif /* HAVE_DEVPOLL */ +} +/* }}} */ + +#if HAVE_DEVPOLL + +/* + * Init module + */ +static int fpm_event_devpoll_init(int max) /* {{{ */ +{ + int i; + + /* open /dev/poll for future usages */ + dpfd = open("/dev/poll", O_RDWR); + if (dpfd < 0) { + zlog(ZLOG_ERROR, "Unable to open /dev/poll"); + return -1; + } + + if (max < 1) { + return 0; + } + + /* alloc and clear pollfds */ + pollfds = malloc(sizeof(struct pollfd) * max); + if (!pollfds) { + zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max); + return -1; + } + memset(pollfds, 0, sizeof(struct pollfd) * max); + + /* set all fd to -1 in order to ensure it's not set */ + for (i = 0; i < max; i++) { + pollfds[i].fd = -1; + } + + /* alloc and clear active_pollfds */ + active_pollfds = malloc(sizeof(struct pollfd) * max); + if (!active_pollfds) { + free(pollfds); + zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max); + return -1; + } + memset(active_pollfds, 0, sizeof(struct pollfd) * max); + + /* save max */ + npollfds = max; + + return 0; +} +/* }}} */ + +/* + * Clean the module + */ +static int fpm_event_devpoll_clean() /* {{{ */ +{ + /* close /dev/poll if open */ + if (dpfd > -1) { + close(dpfd); + dpfd = -1; + } + + /* free pollfds */ + if (pollfds) { + free(pollfds); + pollfds = NULL; + } + + /* free active_pollfds */ + if (active_pollfds) { + free(active_pollfds); + active_pollfds = NULL; + } + + npollfds = 0; + return 0; +} +/* }}} */ + +/* + * wait for events or timeout + */ +static int fpm_event_devpoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */ +{ + int ret, i; + struct fpm_event_queue_s *q; + struct dvpoll dopoll; + + /* setup /dev/poll */ + dopoll.dp_fds = active_pollfds; + dopoll.dp_nfds = npollfds; + dopoll.dp_timeout = (int)timeout; + + /* wait for inconming event or timeout */ + ret = ioctl(dpfd, DP_POLL, &dopoll); + + if (ret < 0) { + + /* trigger error unless signal interrupt */ + if (errno != EINTR) { + zlog(ZLOG_WARNING, "/dev/poll: ioctl() returns %d", errno); + return -1; + } + } + + /* iterate throught triggered events */ + for (i = 0; i < ret; i++) { + + /* find the corresponding event */ + q = queue; + while (q) { + + /* found */ + if (q->ev && q->ev->fd == active_pollfds[i].fd) { + + /* fire the event */ + fpm_event_fire(q->ev); + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return -2; + } + break; /* next triggered event */ + } + q = q->next; /* iterate */ + } + } + + return ret; +} +/* }}} */ + +/* + * Add a FD from the fd set + */ +static int fpm_event_devpoll_add(struct fpm_event_s *ev) /* {{{ */ +{ + struct pollfd pollfd; + + /* fill pollfd with event informations */ + pollfd.fd = ev->fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + + /* add the event to the internal queue */ + if (write(dpfd, &pollfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) { + zlog(ZLOG_ERROR, "/dev/poll: Unable to add the event in the internal queue"); + return -1; + } + + /* mark the event as registered */ + ev->index = ev->fd; + + return 0; +} +/* }}} */ + +/* + * Remove a FD from the fd set + */ +static int fpm_event_devpoll_remove(struct fpm_event_s *ev) /* {{{ */ +{ + struct pollfd pollfd; + + /* fill pollfd with the same informations as fpm_event_devpoll_add */ + pollfd.fd = ev->fd; + pollfd.events = POLLIN | POLLREMOVE; + pollfd.revents = 0; + + /* add the event to the internal queue */ + if (write(dpfd, &pollfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) { + zlog(ZLOG_ERROR, "/dev/poll: Unable to remove the event in the internal queue"); + return -1; + } + + /* mark the event as registered */ + ev->index = -1; + + return 0; +} +/* }}} */ + +#endif /* HAVE_DEVPOLL */ diff --git a/sapi/fpm/fpm/events/devpoll.h b/sapi/fpm/fpm/events/devpoll.h new file mode 100644 index 000000000..95291b158 --- /dev/null +++ b/sapi/fpm/fpm/events/devpoll.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef FPM_EVENTS_DEVPOLL_H +#define FPM_EVENTS_DEVPOLL_H + +#include "../fpm_config.h" +#include "../fpm_events.h" + +struct fpm_event_module_s *fpm_event_devpoll_module(); + +#endif /* FPM_EVENTS_DEVPOLL_H */ diff --git a/sapi/fpm/fpm/events/epoll.c b/sapi/fpm/fpm/events/epoll.c new file mode 100644 index 000000000..2914aa010 --- /dev/null +++ b/sapi/fpm/fpm/events/epoll.c @@ -0,0 +1,211 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "../fpm_config.h" +#include "../fpm_events.h" +#include "../fpm.h" +#include "../zlog.h" + +#if HAVE_EPOLL + +#include <sys/epoll.h> +#include <errno.h> + +static int fpm_event_epoll_init(int max); +static int fpm_event_epoll_clean(); +static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout); +static int fpm_event_epoll_add(struct fpm_event_s *ev); +static int fpm_event_epoll_remove(struct fpm_event_s *ev); + +static struct fpm_event_module_s epoll_module = { + .name = "epoll", + .support_edge_trigger = 1, + .init = fpm_event_epoll_init, + .clean = fpm_event_epoll_clean, + .wait = fpm_event_epoll_wait, + .add = fpm_event_epoll_add, + .remove = fpm_event_epoll_remove, +}; + +static struct epoll_event *epollfds = NULL; +static int nepollfds = 0; +static int epollfd = 0; + +#endif /* HAVE_EPOLL */ + +struct fpm_event_module_s *fpm_event_epoll_module() /* {{{ */ +{ +#if HAVE_EPOLL + return &epoll_module; +#else + return NULL; +#endif /* HAVE_EPOLL */ +} +/* }}} */ + +#if HAVE_EPOLL + +/* + * Init the module + */ +static int fpm_event_epoll_init(int max) /* {{{ */ +{ + if (max < 1) { + return 0; + } + + /* init epoll */ + epollfd = epoll_create(max + 1); + if (epollfd < 0) { + zlog(ZLOG_ERROR, "epoll: unable to initialize"); + return -1; + } + + /* allocate fds */ + epollfds = malloc(sizeof(struct epoll_event) * max); + if (!epollfds) { + zlog(ZLOG_ERROR, "epoll: unable to allocate %d events", max); + return -1; + } + memset(epollfds, 0, sizeof(struct epoll_event) * max); + + /* save max */ + nepollfds = max; + + return 0; +} +/* }}} */ + +/* + * Clean the module + */ +static int fpm_event_epoll_clean() /* {{{ */ +{ + /* free epollfds */ + if (epollfds) { + free(epollfds); + epollfds = NULL; + } + + nepollfds = 0; + + return 0; +} +/* }}} */ + +/* + * wait for events or timeout + */ +static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */ +{ + int ret, i; + + /* ensure we have a clean epoolfds before calling epoll_wait() */ + memset(epollfds, 0, sizeof(struct epoll_event) * nepollfds); + + /* wait for inconming event or timeout */ + ret = epoll_wait(epollfd, epollfds, nepollfds, timeout); + if (ret == -1) { + + /* trigger error unless signal interrupt */ + if (errno != EINTR) { + zlog(ZLOG_WARNING, "epoll_wait() returns %d", errno); + return -1; + } + } + + /* events have been triggered, let's fire them */ + for (i = 0; i < ret; i++) { + + /* do we have a valid ev ptr ? */ + if (!epollfds[i].data.ptr) { + continue; + } + + /* fire the event */ + fpm_event_fire((struct fpm_event_s *)epollfds[i].data.ptr); + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return -2; + } + } + + return ret; +} +/* }}} */ + +/* + * Add a FD to the fd set + */ +static int fpm_event_epoll_add(struct fpm_event_s *ev) /* {{{ */ +{ + struct epoll_event e; + + /* fill epoll struct */ + e.events = EPOLLIN; + e.data.fd = ev->fd; + e.data.ptr = (void *)ev; + + if (ev->flags & FPM_EV_EDGE) { + e.events = e.events | EPOLLET; + } + + /* add the event to epoll internal queue */ + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ev->fd, &e) == -1) { + zlog(ZLOG_ERROR, "epoll: unable to add fd %d", ev->fd); + return -1; + } + + /* mark the event as registered */ + ev->index = ev->fd; + return 0; +} +/* }}} */ + +/* + * Remove a FD from the fd set + */ +static int fpm_event_epoll_remove(struct fpm_event_s *ev) /* {{{ */ +{ + struct epoll_event e; + + /* fill epoll struct the same way we did in fpm_event_epoll_add() */ + e.events = EPOLLIN; + e.data.fd = ev->fd; + e.data.ptr = (void *)ev; + + if (ev->flags & FPM_EV_EDGE) { + e.events = e.events | EPOLLET; + } + + /* remove the event from epoll internal queue */ + if (epoll_ctl(epollfd, EPOLL_CTL_DEL, ev->fd, &e) == -1) { + zlog(ZLOG_ERROR, "epoll: unable to remove fd %d", ev->fd); + return -1; + } + + /* mark the event as not registered */ + ev->index = -1; + return 0; +} +/* }}} */ + +#endif /* HAVE_EPOLL */ diff --git a/sapi/fpm/fpm/events/epoll.h b/sapi/fpm/fpm/events/epoll.h new file mode 100644 index 000000000..63de752fc --- /dev/null +++ b/sapi/fpm/fpm/events/epoll.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef FPM_EVENTS_EPOLL_H +#define FPM_EVENTS_EPOLL_H + +#include "../fpm_config.h" +#include "../fpm_events.h" + +struct fpm_event_module_s *fpm_event_epoll_module(); + +#endif /* FPM_EVENTS_EPOLL_H */ diff --git a/sapi/fpm/fpm/events/kqueue.c b/sapi/fpm/fpm/events/kqueue.c new file mode 100644 index 000000000..eb90c5fcf --- /dev/null +++ b/sapi/fpm/fpm/events/kqueue.c @@ -0,0 +1,208 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "../fpm_config.h" +#include "../fpm_events.h" +#include "../fpm.h" +#include "../zlog.h" + +#if HAVE_KQUEUE + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> + +#include <errno.h> + +static int fpm_event_kqueue_init(int max); +static int fpm_event_kqueue_clean(); +static int fpm_event_kqueue_wait(struct fpm_event_queue_s *queue, unsigned long int timeout); +static int fpm_event_kqueue_add(struct fpm_event_s *ev); +static int fpm_event_kqueue_remove(struct fpm_event_s *ev); + +static struct fpm_event_module_s kqueue_module = { + .name = "kqueue", + .support_edge_trigger = 1, + .init = fpm_event_kqueue_init, + .clean = fpm_event_kqueue_clean, + .wait = fpm_event_kqueue_wait, + .add = fpm_event_kqueue_add, + .remove = fpm_event_kqueue_remove, +}; + +static struct kevent *kevents = NULL; +static int nkevents = 0; +static int kfd = 0; + +#endif /* HAVE_KQUEUE */ + +/* + * Return the module configuration + */ +struct fpm_event_module_s *fpm_event_kqueue_module() /* {{{ */ +{ +#if HAVE_KQUEUE + return &kqueue_module; +#else + return NULL; +#endif /* HAVE_KQUEUE */ +} +/* }}} */ + +#if HAVE_KQUEUE + +/* + * init kqueue and stuff + */ +static int fpm_event_kqueue_init(int max) /* {{{ */ +{ + if (max < 1) { + return 0; + } + + kfd = kqueue(); + if (kfd < 0) { + zlog(ZLOG_ERROR, "kqueue: unable to initialize"); + return -1; + } + + kevents = malloc(sizeof(struct kevent) * max); + if (!kevents) { + zlog(ZLOG_ERROR, "epoll: unable to allocate %d events", max); + return -1; + } + + memset(kevents, 0, sizeof(struct kevent) * max); + + nkevents = max; + + return 0; +} +/* }}} */ + +/* + * release kqueue stuff + */ +static int fpm_event_kqueue_clean() /* {{{ */ +{ + if (kevents) { + free(kevents); + kevents = NULL; + } + + nkevents = 0; + + return 0; +} +/* }}} */ + +/* + * wait for events or timeout + */ +static int fpm_event_kqueue_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */ +{ + struct timespec t; + int ret, i; + + /* ensure we have a clean kevents before calling kevent() */ + memset(kevents, 0, sizeof(struct kevent) * nkevents); + + /* convert ms to timespec struct */ + t.tv_sec = timeout / 1000; + t.tv_nsec = (timeout % 1000) * 1000 * 1000; + + /* wait for incoming event or timeout */ + ret = kevent(kfd, NULL, 0, kevents, nkevents, &t); + if (ret == -1) { + + /* trigger error unless signal interrupt */ + if (errno != EINTR) { + zlog(ZLOG_WARNING, "epoll_wait() returns %d", errno); + return -1; + } + } + + /* fire triggered events */ + for (i = 0; i < ret; i++) { + if (kevents[i].udata) { + struct fpm_event_s *ev = (struct fpm_event_s *)kevents[i].udata; + fpm_event_fire(ev); + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return -2; + } + } + } + + return ret; +} +/* }}} */ + +/* + * Add a FD to to kevent queue + */ +static int fpm_event_kqueue_add(struct fpm_event_s *ev) /* {{{ */ +{ + struct kevent k; + int flags = EV_ADD; + + if (ev->flags & FPM_EV_EDGE) { + flags = flags | EV_CLEAR; + } + + EV_SET(&k, ev->fd, EVFILT_READ, flags, 0, 0, (void *)ev); + + if (kevent(kfd, &k, 1, NULL, 0, NULL) < 0) { + zlog(ZLOG_ERROR, "kevent: unable to add event"); + return -1; + } + + /* mark the event as registered */ + ev->index = ev->fd; + return 0; +} +/* }}} */ + +/* + * Remove a FD from the kevent queue + */ +static int fpm_event_kqueue_remove(struct fpm_event_s *ev) /* {{{ */ +{ + struct kevent k; + int flags = EV_DELETE; + + if (ev->flags & FPM_EV_EDGE) { + flags = flags | EV_CLEAR; + } + + EV_SET(&k, ev->fd, EVFILT_READ, flags, 0, 0, (void *)ev); + + if (kevent(kfd, &k, 1, NULL, 0, NULL) < 0) { + zlog(ZLOG_ERROR, "kevent: unable to add event"); + return -1; + } + + /* mark the vent as not registered */ + ev->index = -1; + return 0; +} +/* }}} */ + +#endif /* HAVE_KQUEUE */ diff --git a/sapi/fpm/fpm/events/kqueue.h b/sapi/fpm/fpm/events/kqueue.h new file mode 100644 index 000000000..aeddce074 --- /dev/null +++ b/sapi/fpm/fpm/events/kqueue.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef FPM_EVENTS_KQUEUE_H +#define FPM_EVENTS_KQUEUE_H + +#include "../fpm_config.h" +#include "../fpm_events.h" + +struct fpm_event_module_s *fpm_event_kqueue_module(); + +#endif /* FPM_EVENTS_KQUEUE_H */ diff --git a/sapi/fpm/fpm/events/poll.c b/sapi/fpm/fpm/events/poll.c new file mode 100644 index 000000000..41ab4ca63 --- /dev/null +++ b/sapi/fpm/fpm/events/poll.c @@ -0,0 +1,276 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "../fpm_config.h" +#include "../fpm_events.h" +#include "../fpm.h" +#include "../zlog.h" + +#if HAVE_POLL + +#include <poll.h> +#include <errno.h> +#include <string.h> + +static int fpm_event_poll_init(int max); +static int fpm_event_poll_clean(); +static int fpm_event_poll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout); +static int fpm_event_poll_add(struct fpm_event_s *ev); +static int fpm_event_poll_remove(struct fpm_event_s *ev); + +static struct fpm_event_module_s poll_module = { + .name = "poll", + .support_edge_trigger = 0, + .init = fpm_event_poll_init, + .clean = fpm_event_poll_clean, + .wait = fpm_event_poll_wait, + .add = fpm_event_poll_add, + .remove = fpm_event_poll_remove, +}; + +static struct pollfd *pollfds = NULL; +static struct pollfd *active_pollfds = NULL; +static int npollfds = 0; +static int next_free_slot = 0; +#endif /* HAVE_POLL */ + +/* + * return the module configuration + */ +struct fpm_event_module_s *fpm_event_poll_module() /* {{{ */ +{ +#if HAVE_POLL + return &poll_module; +#else + return NULL; +#endif /* HAVE_POLL */ +} +/* }}} */ + +#if HAVE_POLL + +/* + * Init the module + */ +static int fpm_event_poll_init(int max) /* {{{ */ +{ + int i; + + if (max < 1) { + return 0; + } + + /* alloc and clear pollfds */ + pollfds = malloc(sizeof(struct pollfd) * max); + if (!pollfds) { + zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max); + return -1; + } + memset(pollfds, 0, sizeof(struct pollfd) * max); + + /* set all fd to -1 in order to ensure it's not set */ + for (i = 0; i < max; i++) { + pollfds[i].fd = -1; + } + + /* alloc and clear active_pollfds */ + active_pollfds = malloc(sizeof(struct pollfd) * max); + if (!active_pollfds) { + free(pollfds); + zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max); + return -1; + } + memset(active_pollfds, 0, sizeof(struct pollfd) * max); + + /* save max */ + npollfds = max; + return 0; +} +/* }}} */ + +/* + * Clean the module + */ +static int fpm_event_poll_clean() /* {{{ */ +{ + /* free pollfds */ + if (pollfds) { + free(pollfds); + pollfds = NULL; + } + + /* free active_pollfds */ + if (active_pollfds) { + free(active_pollfds); + active_pollfds = NULL; + } + + npollfds = 0; + return 0; +} +/* }}} */ + +/* + * wait for events or timeout + */ +static int fpm_event_poll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */ +{ + int ret; + struct fpm_event_queue_s *q; + + if (npollfds > 0) { + /* copy pollfds because poll() alters it */ + memcpy(active_pollfds, pollfds, sizeof(struct pollfd) * npollfds); + } + + /* wait for inconming event or timeout */ + ret = poll(active_pollfds, npollfds, timeout); + if (ret == -1) { + + /* trigger error unless signal interrupt */ + if (errno != EINTR) { + zlog(ZLOG_WARNING, "poll() returns %d", errno); + return -1; + } + } + + /* events have been triggered */ + if (ret > 0) { + + /* trigger POLLIN events */ + q = queue; + while (q) { + /* ensure ev->index is valid */ + if (q->ev && q->ev->index >= 0 && q->ev->index < npollfds && q->ev->fd == active_pollfds[q->ev->index].fd) { + + /* has the event has been triggered ? */ + if (active_pollfds[q->ev->index].revents & POLLIN) { + + /* fire the event */ + fpm_event_fire(q->ev); + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return -2; + } + } + } + q = q->next; /* iterate */ + } + } + + return ret; +} +/* }}} */ + +/* + * Add a FD to the fd set + */ +static int fpm_event_poll_add(struct fpm_event_s *ev) /* {{{ */ +{ + int i; + + /* do we have a direct free slot */ + if (pollfds[next_free_slot].fd == -1) { + /* register the event */ + pollfds[next_free_slot].fd = ev->fd; + pollfds[next_free_slot].events = POLLIN; + + /* remember the event place in the fd list and suppose next slot is free */ + ev->index = next_free_slot++; + if (next_free_slot >= npollfds) { + next_free_slot = 0; + } + return 0; + } + + /* let's search */ + for (i = 0; i < npollfds; i++) { + if (pollfds[i].fd != -1) { + /* not free */ + continue; + } + + /* register the event */ + pollfds[i].fd = ev->fd; + pollfds[i].events = POLLIN; + + /* remember the event place in the fd list and suppose next slot is free */ + ev->index = next_free_slot++; + if (next_free_slot >= npollfds) { + next_free_slot = 0; + } + return 0; + } + + zlog(ZLOG_ERROR, "poll: not enought space to add event (fd=%d)", ev->fd); + return -1; +} +/* }}} */ + +/* + * Remove a FD from the fd set + */ +static int fpm_event_poll_remove(struct fpm_event_s *ev) /* {{{ */ +{ + int i; + + /* do we have a direct access */ + if (ev->index >= 0 && ev->index < npollfds && pollfds[ev->index].fd == ev->fd) { + /* remember this slot as free */ + next_free_slot = ev->index; + + /* clear event in pollfds */ + pollfds[ev->index].fd = -1; + pollfds[ev->index].events = 0; + + /* mark the event as not registered */ + ev->index = -1; + + return 0; + } + + /* let's search */ + for (i = 0; i < npollfds; i++) { + + if (pollfds[i].fd != ev->fd) { + /* not found */ + continue; + } + + /* remember this slot as free */ + next_free_slot = i; + + /* clear event in pollfds */ + pollfds[i].fd = -1; + pollfds[i].events = 0; + + /* mark the event as not registered */ + ev->index = -1; + + return 0; + } + + zlog(ZLOG_ERROR, "poll: unable to remove event: not found (fd=%d, index=%d)", ev->fd, ev->index); + return -1; +} +/* }}} */ + +#endif /* HAVE_POLL */ diff --git a/sapi/fpm/fpm/events/poll.h b/sapi/fpm/fpm/events/poll.h new file mode 100644 index 000000000..601a03b3a --- /dev/null +++ b/sapi/fpm/fpm/events/poll.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef FPM_EVENTS_POLL_H +#define FPM_EVENTS_POLL_H + +#include "../fpm_config.h" +#include "../fpm_events.h" + +struct fpm_event_module_s *fpm_event_poll_module(); + +#endif /* FPM_EVENTS_POLL_H */ diff --git a/sapi/fpm/fpm/events/port.c b/sapi/fpm/fpm/events/port.c new file mode 100644 index 000000000..6564ff245 --- /dev/null +++ b/sapi/fpm/fpm/events/port.c @@ -0,0 +1,185 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "../fpm_config.h" +#include "../fpm_events.h" +#include "../fpm.h" +#include "../zlog.h" + +#if HAVE_PORT + +#include <port.h> +#include <poll.h> +#include <errno.h> + +static int fpm_event_port_init(int max); +static int fpm_event_port_clean(); +static int fpm_event_port_wait(struct fpm_event_queue_s *queue, unsigned long int timeout); +static int fpm_event_port_add(struct fpm_event_s *ev); +static int fpm_event_port_remove(struct fpm_event_s *ev); + +static struct fpm_event_module_s port_module = { + .name = "port", + .support_edge_trigger = 0, + .init = fpm_event_port_init, + .clean = fpm_event_port_clean, + .wait = fpm_event_port_wait, + .add = fpm_event_port_add, + .remove = fpm_event_port_remove, +}; + +port_event_t *events = NULL; +int nevents = 0; +static int pfd = -1; + +#endif /* HAVE_PORT */ + +struct fpm_event_module_s *fpm_event_port_module() /* {{{ */ +{ +#if HAVE_PORT + return &port_module; +#else + return NULL; +#endif /* HAVE_PORT */ +} +/* }}} */ + +#if HAVE_PORT + +/* + * Init the module + */ +static int fpm_event_port_init(int max) /* {{{ */ +{ + /* open port */ + pfd = port_create(); + if (pfd < 0) { + zlog(ZLOG_ERROR, "port: unable to initialize port_create()"); + return -1; + } + + if (max < 1) { + return 0; + } + + /* alloc and clear active_pollfds */ + events = malloc(sizeof(port_event_t) * max); + if (!events) { + zlog(ZLOG_ERROR, "port: Unable to allocate %d events", max); + return -1; + } + + nevents = max; + return 0; +} +/* }}} */ + +/* + * Clean the module + */ +static int fpm_event_port_clean() /* {{{ */ +{ + if (pfd > -1) { + close(pfd); + pfd = -1; + } + + if (events) { + free(events); + events = NULL; + } + + nevents = 0; + return 0; +} +/* }}} */ + +/* + * wait for events or timeout + */ +static int fpm_event_port_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */ +{ + int ret, i, nget; + timespec_t t; + + /* convert timeout into timespec_t */ + t.tv_sec = (int)(timeout / 1000); + t.tv_nsec = (timeout % 1000) * 1000 * 1000; + + /* wait for inconming event or timeout. We want at least one event or timeout */ + nget = 1; + ret = port_getn(pfd, events, nevents, &nget, &t); + if (ret < 0) { + + /* trigger error unless signal interrupt or timeout */ + if (errno != EINTR && errno != ETIME) { + zlog(ZLOG_WARNING, "poll() returns %d", errno); + return -1; + } + } + + for (i = 0; i < nget; i++) { + + /* do we have a ptr to the event ? */ + if (!events[i].portev_user) { + continue; + } + + /* fire the event */ + fpm_event_fire((struct fpm_event_s *)events[i].portev_user); + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return -2; + } + } + return nget; +} +/* }}} */ + +/* + * Add a FD to the fd set + */ +static int fpm_event_port_add(struct fpm_event_s *ev) /* {{{ */ +{ + /* add the event to port */ + if (port_associate(pfd, PORT_SOURCE_FD, ev->fd, POLLIN, (void *)ev) < 0) { + zlog(ZLOG_ERROR, "port: unable to add the event"); + return -1; + } + return 0; +} +/* }}} */ + +/* + * Remove a FD from the fd set + */ +static int fpm_event_port_remove(struct fpm_event_s *ev) /* {{{ */ +{ + /* remove the event from port */ + if (port_dissociate(pfd, PORT_SOURCE_FD, ev->fd) < 0) { + zlog(ZLOG_ERROR, "port: unable to add the event"); + return -1; + } + return 0; +} +/* }}} */ + +#endif /* HAVE_PORT */ diff --git a/sapi/fpm/fpm/events/port.h b/sapi/fpm/fpm/events/port.h new file mode 100644 index 000000000..a48b3f624 --- /dev/null +++ b/sapi/fpm/fpm/events/port.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef FPM_EVENTS_PORT_H +#define FPM_EVENTS_PORT_H + +#include "../fpm_config.h" +#include "../fpm_events.h" + +struct fpm_event_module_s *fpm_event_port_module(); + +#endif /* FPM_EVENTS_PORT_H */ diff --git a/sapi/fpm/fpm/events/select.c b/sapi/fpm/fpm/events/select.c new file mode 100644 index 000000000..03a715840 --- /dev/null +++ b/sapi/fpm/fpm/events/select.c @@ -0,0 +1,175 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "../fpm_config.h" +#include "../fpm_events.h" +#include "../fpm.h" +#include "../zlog.h" + +#if HAVE_SELECT + +/* According to POSIX.1-2001 */ +#include <sys/select.h> + +/* According to earlier standards */ +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <errno.h> + +static int fpm_event_select_init(int max); +static int fpm_event_select_wait(struct fpm_event_queue_s *queue, unsigned long int timeout); +static int fpm_event_select_add(struct fpm_event_s *ev); +static int fpm_event_select_remove(struct fpm_event_s *ev); + +static struct fpm_event_module_s select_module = { + .name = "select", + .support_edge_trigger = 0, + .init = fpm_event_select_init, + .clean = NULL, + .wait = fpm_event_select_wait, + .add = fpm_event_select_add, + .remove = fpm_event_select_remove, +}; + +static fd_set fds; + +#endif /* HAVE_SELECT */ + +/* + * return the module configuration + */ +struct fpm_event_module_s *fpm_event_select_module() /* {{{ */ +{ +#if HAVE_SELECT + return &select_module; +#else + return NULL; +#endif /* HAVE_SELECT */ +} +/* }}} */ + +#if HAVE_SELECT + +/* + * Init the module + */ +static int fpm_event_select_init(int max) /* {{{ */ +{ + FD_ZERO(&fds); + return 0; +} +/* }}} */ + + +/* + * wait for events or timeout + */ +static int fpm_event_select_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */ +{ + int ret; + struct fpm_event_queue_s *q; + fd_set current_fds; + struct timeval t; + + /* copy fds because select() alters it */ + current_fds = fds; + + /* fill struct timeval with timeout */ + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + + /* wait for inconming event or timeout */ + ret = select(FD_SETSIZE, ¤t_fds, NULL, NULL, &t); + if (ret == -1) { + + /* trigger error unless signal interrupt */ + if (errno != EINTR) { + zlog(ZLOG_WARNING, "poll() returns %d", errno); + return -1; + } + } + + /* events have been triggered */ + if (ret > 0) { + + /* trigger POLLIN events */ + q = queue; + while (q) { + if (q->ev) { /* sanity check */ + + /* check if the event has been triggered */ + if (FD_ISSET(q->ev->fd, ¤t_fds)) { + + /* fire the event */ + fpm_event_fire(q->ev); + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return -2; + } + } + } + q = q->next; /* iterate */ + } + } + return ret; + +} +/* }}} */ + +/* + * Add a FD to the fd set + */ +static int fpm_event_select_add(struct fpm_event_s *ev) /* {{{ */ +{ + /* check size limitation */ + if (ev->fd >= FD_SETSIZE) { + zlog(ZLOG_ERROR, "select: not enough space in the select fd list (max = %d). Please consider using another event mechanism.", FD_SETSIZE); + return -1; + } + + /* add the FD if not already in */ + if (!FD_ISSET(ev->fd, &fds)) { + FD_SET(ev->fd, &fds); + ev->index = ev->fd; + } + + return 0; +} +/* }}} */ + +/* + * Remove a FD from the fd set + */ +static int fpm_event_select_remove(struct fpm_event_s *ev) /* {{{ */ +{ + /* remove the fd if it's in */ + if (FD_ISSET(ev->fd, &fds)) { + FD_CLR(ev->fd, &fds); + ev->index = -1; + } + + return 0; +} +/* }}} */ + +#endif /* HAVE_SELECT */ diff --git a/sapi/fpm/fpm/events/select.h b/sapi/fpm/fpm/events/select.h new file mode 100644 index 000000000..6fda70fbd --- /dev/null +++ b/sapi/fpm/fpm/events/select.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2012 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Jerome Loyet <jerome@loyet.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef FPM_EVENTS_SELECT_H +#define FPM_EVENTS_SELECT_H + +#include "../fpm_config.h" +#include "../fpm_events.h" + +struct fpm_event_module_s *fpm_event_select_module(); + +#endif /* FPM_EVENTS_SELECT_H */ diff --git a/sapi/fpm/fpm/fastcgi.c b/sapi/fpm/fpm/fastcgi.c index 22a8f3a2f..212b6ff1d 100644 --- a/sapi/fpm/fpm/fastcgi.c +++ b/sapi/fpm/fpm/fastcgi.c @@ -29,9 +29,9 @@ #include <limits.h> #include <php_config.h> -#include <fpm/fpm.h> -#include <fpm/fpm_request.h> -#include <fpm/zlog.h> +#include "fpm.h" +#include "fpm_request.h" +#include "zlog.h" #ifdef _WIN32 @@ -142,7 +142,6 @@ typedef union _sa_t { static HashTable fcgi_mgmt_vars; static int is_initialized = 0; -static int is_fastcgi = 0; static int in_shutdown = 0; static in_addr_t *allowed_clients = NULL; @@ -186,10 +185,6 @@ static void fcgi_setup_signals(void) int fcgi_init(void) { if (!is_initialized) { -#ifndef _WIN32 - sa_t sa; - socklen_t len = sizeof(sa); -#endif zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1); fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS") - 1, "0", sizeof("0")-1); @@ -204,9 +199,7 @@ int fcgi_init(void) return 0; } # endif - if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) && - (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) && - (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) { + { char *str; DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT; HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE); @@ -225,36 +218,14 @@ int fcgi_init(void) if (str != NULL) { fcgi_accept_mutex = (HANDLE) atoi(str); } - return is_fastcgi = 1; - } else { - return is_fastcgi = 0; + return 1; } #else - errno = 0; - if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) { - fcgi_setup_signals(); - return is_fastcgi = 1; - } else { - return is_fastcgi = 0; - } + fcgi_setup_signals(); + return 1; #endif } - return is_fastcgi; -} - - -int fcgi_is_fastcgi(void) -{ - if (!is_initialized) { - return fcgi_init(); - } else { - return is_fastcgi; - } -} - -void fcgi_set_is_fastcgi(int new_value) -{ - is_fastcgi = new_value; + return 1; } void fcgi_set_in_shutdown(int new_value) @@ -267,7 +238,6 @@ void fcgi_shutdown(void) if (is_initialized) { zend_hash_destroy(&fcgi_mgmt_vars); } - is_fastcgi = 0; if (allowed_clients) { free(allowed_clients); } @@ -298,7 +268,7 @@ void fcgi_set_allowed_clients(char *ip) } allowed_clients[n] = inet_addr(cur); if (allowed_clients[n] == INADDR_NONE) { - fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS or listen.allowed_clients\n", cur); + zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur); } n++; cur = end; @@ -846,7 +816,7 @@ int fcgi_accept_request(fcgi_request *req) n++; } if (!allowed) { - fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr)); + zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr)); closesocket(req->fd); req->fd = -1; continue; @@ -902,7 +872,7 @@ int fcgi_accept_request(fcgi_request *req) } fcgi_close(req, 1, 0); } else { - fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded."); + zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded."); fcgi_close(req, 1, 0); } #endif @@ -976,7 +946,7 @@ int fcgi_flush(fcgi_request *req, int close) return 1; } -int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len) +ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len) { int limit, rest; diff --git a/sapi/fpm/fpm/fastcgi.h b/sapi/fpm/fpm/fastcgi.h index 4129def05..7a9f3ef36 100644 --- a/sapi/fpm/fpm/fastcgi.h +++ b/sapi/fpm/fpm/fastcgi.h @@ -114,12 +114,10 @@ typedef struct _fcgi_request { int fcgi_init(void); void fcgi_shutdown(void); -int fcgi_is_fastcgi(void); void fcgi_init_request(fcgi_request *req, int listen_socket); int fcgi_accept_request(fcgi_request *req); int fcgi_finish_request(fcgi_request *req, int force_close); -void fcgi_set_is_fastcgi(int new_value); void fcgi_set_in_shutdown(int); void fcgi_set_allowed_clients(char *); void fcgi_close(fcgi_request *req, int force, int destroy); @@ -129,7 +127,7 @@ char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val); int fcgi_read(fcgi_request *req, char *str, int len); -int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len); +ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len); int fcgi_flush(fcgi_request *req, int close); void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len); diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c index 57efcfd75..96aabbfc4 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -36,7 +36,8 @@ struct fpm_globals_s fpm_globals = { .listening_socket = 0, .max_requests = 0, .is_child = 0, - .test_successful = 0 + .test_successful = 0, + .heartbeat = 0 }; int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf) /* {{{ */ @@ -51,7 +52,6 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t if (0 > fpm_php_init_main() || 0 > fpm_stdio_init_main() || - 0 > fpm_log_init_main() || 0 > fpm_conf_init_main(test_conf) || 0 > fpm_unix_init_main() || 0 > fpm_scoreboard_init_main() || @@ -66,11 +66,13 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t if (fpm_globals.test_successful) { exit(0); } else { + zlog(ZLOG_ERROR, "FPM initialization failed"); return -1; } } if (0 > fpm_conf_write_pid()) { + zlog(ZLOG_ERROR, "FPM initialization failed"); return -1; } diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h index 3c6f798fb..bfeac4d67 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -24,6 +24,7 @@ struct fpm_globals_s { int max_requests; /* for this child */ int is_child; int test_successful; + int heartbeat; }; extern struct fpm_globals_s fpm_globals; diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index 94580194f..35058b0ea 100644 --- a/sapi/fpm/fpm/fpm_children.c +++ b/sapi/fpm/fpm/fpm_children.c @@ -147,13 +147,13 @@ static void fpm_child_init(struct fpm_worker_pool_s *wp) /* {{{ */ { fpm_globals.max_requests = wp->config->pm_max_requests; - if (0 > fpm_stdio_init_child(wp) || - 0 > fpm_log_init_child(wp) || - 0 > fpm_status_init_child(wp) || - 0 > fpm_unix_init_child(wp) || - 0 > fpm_signals_init_child() || - 0 > fpm_env_init_child(wp) || - 0 > fpm_php_init_child(wp)) { + if (0 > fpm_stdio_init_child(wp) || + 0 > fpm_log_init_child(wp) || + 0 > fpm_status_init_child(wp) || + 0 > fpm_unix_init_child(wp) || + 0 > fpm_signals_init_child() || + 0 > fpm_env_init_child(wp) || + 0 > fpm_php_init_child(wp)) { zlog(ZLOG_ERROR, "[pool %s] child failed to initialize", wp->config->name); exit(255); @@ -292,7 +292,7 @@ void fpm_children_bury() /* {{{ */ } } } else { - zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s", pid, buf); + zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s. Please open a bug report (https://bugs.php.net).", pid, buf); } } } @@ -305,7 +305,7 @@ static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) / c = fpm_child_alloc(); if (!c) { - zlog(ZLOG_ERROR, "[pool %s] malloc failed", wp->config->name); + zlog(ZLOG_ERROR, "[pool %s] unable to malloc new child", wp->config->name); return 0; } @@ -344,6 +344,7 @@ static void fpm_child_resources_use(struct fpm_child_s *child) /* {{{ */ } fpm_scoreboard_free(wp->scoreboard); } + fpm_scoreboard_child_use(child->wp->scoreboard, child->scoreboard_i, getpid()); fpm_stdio_child_use_pipes(child); fpm_child_free(child); @@ -362,6 +363,7 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to pid_t pid; struct fpm_child_s *child; int max; + static int warned = 0; if (wp->config->pm == PM_STYLE_DYNAMIC) { if (!in_event_loop) { /* starting */ @@ -369,11 +371,26 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to } else { max = wp->running_children + nb_to_spawn; } + } else if (wp->config->pm == PM_STYLE_ONDEMAND) { + if (!in_event_loop) { /* starting */ + max = 0; /* do not create any child at startup */ + } else { + max = wp->running_children + nb_to_spawn; + } } else { /* PM_STYLE_STATIC */ max = wp->config->pm_max_children; } - while (fpm_pctl_can_spawn_children() && wp->running_children < max) { + /* + * fork children while: + * - fpm_pctl_can_spawn_children : FPM is running in a NORMAL state (aka not restart, stop or reload) + * - wp->running_children < max : there is less than the max process for the current pool + * - (fpm_global_config.process_max < 1 || fpm_globals.running_children < fpm_global_config.process_max): + * if fpm_global_config.process_max is set, FPM has not fork this number of processes (globaly) + */ + while (fpm_pctl_can_spawn_children() && wp->running_children < max && (fpm_global_config.process_max < 1 || fpm_globals.running_children < fpm_global_config.process_max)) { + + warned = 0; child = fpm_resources_prepare(wp); if (!child) { @@ -406,12 +423,33 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to } + if (!warned && fpm_global_config.process_max > 0 && fpm_globals.running_children >= fpm_global_config.process_max) { + warned = 1; + zlog(ZLOG_WARNING, "The maximum number of processes has been reached. Please review your configuration and consider raising 'process.max'"); + } + return 1; /* we are done */ } /* }}} */ int fpm_children_create_initial(struct fpm_worker_pool_s *wp) /* {{{ */ { + if (wp->config->pm == PM_STYLE_ONDEMAND) { + wp->ondemand_event = (struct fpm_event_s *)malloc(sizeof(struct fpm_event_s)); + + if (!wp->ondemand_event) { + zlog(ZLOG_ERROR, "[pool %s] unable to malloc the ondemand socket event", wp->config->name); + // FIXME handle crash + return 1; + } + + memset(wp->ondemand_event, 0, sizeof(struct fpm_event_s)); + fpm_event_set(wp->ondemand_event, wp->listening_socket, FPM_EV_READ | FPM_EV_EDGE, fpm_pctl_on_socket_accept, wp); + wp->socket_event_set = 1; + fpm_event_add(wp->ondemand_event, 0); + + return 1; + } return fpm_children_make(wp, 0 /* not in event loop yet */, 0, 1); } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_cleanup.c b/sapi/fpm/fpm/fpm_cleanup.c index 3f59e6585..260ddb32e 100644 --- a/sapi/fpm/fpm/fpm_cleanup.c +++ b/sapi/fpm/fpm/fpm_cleanup.c @@ -8,7 +8,6 @@ #include "fpm_arrays.h" #include "fpm_cleanup.h" -#include "zlog.h" struct cleanup_s { int type; diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index 6a37ae27f..61f066fc9 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -31,6 +31,7 @@ #include "zend_ini_scanner.h" #include "zend_globals.h" #include "zend_stream.h" +#include "php_syslog.h" #include "fpm.h" #include "fpm_conf.h" @@ -42,72 +43,96 @@ #include "fpm_shm.h" #include "fpm_status.h" #include "fpm_log.h" +#include "fpm_events.h" #include "zlog.h" #define STR2STR(a) (a ? a : "undefined") #define BOOL2STR(a) (a ? "yes" : "no") -#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : "dynamic") #define GO(field) offsetof(struct fpm_global_config_s, field) #define WPO(field) offsetof(struct fpm_worker_pool_config_s, field) static int fpm_conf_load_ini_file(char *filename TSRMLS_DC); static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset); +static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset); +#ifdef HAVE_SYSLOG_H +static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset); +#endif -struct fpm_global_config_s fpm_global_config = { .daemonize = 1 }; +struct fpm_global_config_s fpm_global_config = { + .daemonize = 1, +#ifdef HAVE_SYSLOG_H + .syslog_facility = -1, +#endif + .process_max = 0, +}; static struct fpm_worker_pool_s *current_wp = NULL; static int ini_recursion = 0; static char *ini_filename = NULL; static int ini_lineno = 0; static char *ini_include = NULL; +/* + * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in + */ static struct ini_value_parser_s ini_fpm_global_options[] = { - { "emergency_restart_threshold", &fpm_conf_set_integer, GO(emergency_restart_threshold) }, - { "emergency_restart_interval", &fpm_conf_set_time, GO(emergency_restart_interval) }, - { "process_control_timeout", &fpm_conf_set_time, GO(process_control_timeout) }, - { "daemonize", &fpm_conf_set_boolean, GO(daemonize) }, - { "pid", &fpm_conf_set_string, GO(pid_file) }, - { "error_log", &fpm_conf_set_string, GO(error_log) }, - { "log_level", &fpm_conf_set_log_level, 0 }, - { "rlimit_files", &fpm_conf_set_integer, GO(rlimit_files) }, - { "rlimit_core", &fpm_conf_set_rlimit_core, GO(rlimit_core) }, + { "pid", &fpm_conf_set_string, GO(pid_file) }, + { "error_log", &fpm_conf_set_string, GO(error_log) }, +#ifdef HAVE_SYSLOG_H + { "syslog.ident", &fpm_conf_set_string, GO(syslog_ident) }, + { "syslog.facility", &fpm_conf_set_syslog_facility, GO(syslog_facility) }, +#endif + { "log_level", &fpm_conf_set_log_level, GO(log_level) }, + { "emergency_restart_threshold", &fpm_conf_set_integer, GO(emergency_restart_threshold) }, + { "emergency_restart_interval", &fpm_conf_set_time, GO(emergency_restart_interval) }, + { "process_control_timeout", &fpm_conf_set_time, GO(process_control_timeout) }, + { "process.max", &fpm_conf_set_integer, GO(process_max) }, + { "daemonize", &fpm_conf_set_boolean, GO(daemonize) }, + { "rlimit_files", &fpm_conf_set_integer, GO(rlimit_files) }, + { "rlimit_core", &fpm_conf_set_rlimit_core, GO(rlimit_core) }, + { "events.mechanism", &fpm_conf_set_string, GO(events_mechanism) }, { 0, 0, 0 } }; +/* + * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in + */ static struct ini_value_parser_s ini_fpm_pool_options[] = { { "prefix", &fpm_conf_set_string, WPO(prefix) }, { "user", &fpm_conf_set_string, WPO(user) }, { "group", &fpm_conf_set_string, WPO(group) }, - { "chroot", &fpm_conf_set_string, WPO(chroot) }, - { "chdir", &fpm_conf_set_string, WPO(chdir) }, - { "request_terminate_timeout", &fpm_conf_set_time, WPO(request_terminate_timeout) }, - { "request_slowlog_timeout", &fpm_conf_set_time, WPO(request_slowlog_timeout) }, - { "slowlog", &fpm_conf_set_string, WPO(slowlog) }, - { "rlimit_files", &fpm_conf_set_integer, WPO(rlimit_files) }, - { "rlimit_core", &fpm_conf_set_rlimit_core, WPO(rlimit_core) }, - { "catch_workers_output", &fpm_conf_set_boolean, WPO(catch_workers_output) }, { "listen", &fpm_conf_set_string, WPO(listen_address) }, + { "listen.backlog", &fpm_conf_set_integer, WPO(listen_backlog) }, { "listen.owner", &fpm_conf_set_string, WPO(listen_owner) }, { "listen.group", &fpm_conf_set_string, WPO(listen_group) }, { "listen.mode", &fpm_conf_set_string, WPO(listen_mode) }, - { "listen.backlog", &fpm_conf_set_integer, WPO(listen_backlog) }, { "listen.allowed_clients", &fpm_conf_set_string, WPO(listen_allowed_clients) }, { "pm", &fpm_conf_set_pm, WPO(pm) }, - { "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) }, { "pm.max_children", &fpm_conf_set_integer, WPO(pm_max_children) }, { "pm.start_servers", &fpm_conf_set_integer, WPO(pm_start_servers) }, { "pm.min_spare_servers", &fpm_conf_set_integer, WPO(pm_min_spare_servers) }, { "pm.max_spare_servers", &fpm_conf_set_integer, WPO(pm_max_spare_servers) }, + { "pm.process_idle_timeout", &fpm_conf_set_time, WPO(pm_process_idle_timeout) }, + { "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) }, { "pm.status_path", &fpm_conf_set_string, WPO(pm_status_path) }, { "ping.path", &fpm_conf_set_string, WPO(ping_path) }, { "ping.response", &fpm_conf_set_string, WPO(ping_response) }, { "access.log", &fpm_conf_set_string, WPO(access_log) }, { "access.format", &fpm_conf_set_string, WPO(access_format) }, + { "slowlog", &fpm_conf_set_string, WPO(slowlog) }, + { "request_slowlog_timeout", &fpm_conf_set_time, WPO(request_slowlog_timeout) }, + { "request_terminate_timeout", &fpm_conf_set_time, WPO(request_terminate_timeout) }, + { "rlimit_files", &fpm_conf_set_integer, WPO(rlimit_files) }, + { "rlimit_core", &fpm_conf_set_rlimit_core, WPO(rlimit_core) }, + { "chroot", &fpm_conf_set_string, WPO(chroot) }, + { "chdir", &fpm_conf_set_string, WPO(chdir) }, + { "catch_workers_output", &fpm_conf_set_boolean, WPO(catch_workers_output) }, + { "security.limit_extensions", &fpm_conf_set_string, WPO(security_limit_extensions) }, { 0, 0, 0 } }; @@ -174,21 +199,25 @@ static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset) / static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset) /* {{{ */ { - char *new; - char **old = (char **) ((char *) *config + offset); - if (*old) { - return "it's already been defined. Can't do that twice."; + char **config_val = (char **) ((char *) *config + offset); + + if (!config_val) { + return "internal error: NULL value"; + } + + /* Check if there is a previous value to deallocate */ + if (*config_val) { + free(*config_val); } - new = strdup(Z_STRVAL_P(value)); - if (!new) { + *config_val = strdup(Z_STRVAL_P(value)); + if (!*config_val) { return "fpm_conf_set_string(): strdup() failed"; } - if (fpm_conf_expand_pool_name(&new) == -1) { + if (fpm_conf_expand_pool_name(config_val) == -1) { return "Can't use '$pool' when the pool is not defined"; } - *old = new; return NULL; } /* }}} */ @@ -198,8 +227,9 @@ static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset) / char *val = Z_STRVAL_P(value); char *p; + /* we don't use strtol because we don't want to allow negative values */ for (p = val; *p; p++) { - if ( p == val && *p == '-' ) continue; + if (p == val && *p == '-') continue; if (*p < '0' || *p > '9') { return "is not a valid number (greater or equal than zero)"; } @@ -209,6 +239,22 @@ static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset) / } /* }}} */ +static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset) /* {{{ */ +{ + char *val = Z_STRVAL_P(value); + char *p; + + for (p = val; *p; p++) { + if ( p == val && *p == '-' ) continue; + if (*p < '0' || *p > '9') { + return "is not a valid number (greater or equal than zero)"; + } + } + * (long int *) ((char *) *config + offset) = atol(val); + return NULL; +} +/* }}} */ + static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); @@ -252,25 +298,178 @@ static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* { static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); + int log_level; if (!strcasecmp(val, "debug")) { - fpm_globals.log_level = ZLOG_DEBUG; + log_level = ZLOG_DEBUG; } else if (!strcasecmp(val, "notice")) { - fpm_globals.log_level = ZLOG_NOTICE; + log_level = ZLOG_NOTICE; } else if (!strcasecmp(val, "warning") || !strcasecmp(val, "warn")) { - fpm_globals.log_level = ZLOG_WARNING; + log_level = ZLOG_WARNING; } else if (!strcasecmp(val, "error")) { - fpm_globals.log_level = ZLOG_ERROR; + log_level = ZLOG_ERROR; } else if (!strcasecmp(val, "alert")) { - fpm_globals.log_level = ZLOG_ALERT; + log_level = ZLOG_ALERT; } else { return "invalid value for 'log_level'"; } + * (int *) ((char *) *config + offset) = log_level; return NULL; } /* }}} */ +#ifdef HAVE_SYSLOG_H +static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset) /* {{{ */ +{ + char *val = Z_STRVAL_P(value); + int *conf = (int *) ((char *) *config + offset); + +#ifdef LOG_AUTH + if (!strcasecmp(val, "AUTH")) { + *conf = LOG_AUTH; + return NULL; + } +#endif + +#ifdef LOG_AUTHPRIV + if (!strcasecmp(val, "AUTHPRIV")) { + *conf = LOG_AUTHPRIV; + return NULL; + } +#endif + +#ifdef LOG_CRON + if (!strcasecmp(val, "CRON")) { + *conf = LOG_CRON; + return NULL; + } +#endif + +#ifdef LOG_DAEMON + if (!strcasecmp(val, "DAEMON")) { + *conf = LOG_DAEMON; + return NULL; + } +#endif + +#ifdef LOG_FTP + if (!strcasecmp(val, "FTP")) { + *conf = LOG_FTP; + return NULL; + } +#endif + +#ifdef LOG_KERN + if (!strcasecmp(val, "KERN")) { + *conf = LOG_KERN; + return NULL; + } +#endif + +#ifdef LOG_LPR + if (!strcasecmp(val, "LPR")) { + *conf = LOG_LPR; + return NULL; + } +#endif + +#ifdef LOG_MAIL + if (!strcasecmp(val, "MAIL")) { + *conf = LOG_MAIL; + return NULL; + } +#endif + +#ifdef LOG_NEWS + if (!strcasecmp(val, "NEWS")) { + *conf = LOG_NEWS; + return NULL; + } +#endif + +#ifdef LOG_SYSLOG + if (!strcasecmp(val, "SYSLOG")) { + *conf = LOG_SYSLOG; + return NULL; + } +#endif + +#ifdef LOG_USER + if (!strcasecmp(val, "USER")) { + *conf = LOG_USER; + return NULL; + } +#endif + +#ifdef LOG_UUCP + if (!strcasecmp(val, "UUCP")) { + *conf = LOG_UUCP; + return NULL; + } +#endif + +#ifdef LOG_LOCAL0 + if (!strcasecmp(val, "LOCAL0")) { + *conf = LOG_LOCAL0; + return NULL; + } +#endif + +#ifdef LOG_LOCAL1 + if (!strcasecmp(val, "LOCAL1")) { + *conf = LOG_LOCAL1; + return NULL; + } +#endif + +#ifdef LOG_LOCAL2 + if (!strcasecmp(val, "LOCAL2")) { + *conf = LOG_LOCAL2; + return NULL; + } +#endif + +#ifdef LOG_LOCAL3 + if (!strcasecmp(val, "LOCAL3")) { + *conf = LOG_LOCAL3; + return NULL; + } +#endif + +#ifdef LOG_LOCAL4 + if (!strcasecmp(val, "LOCAL4")) { + *conf = LOG_LOCAL4; + return NULL; + } +#endif + +#ifdef LOG_LOCAL5 + if (!strcasecmp(val, "LOCAL5")) { + *conf = LOG_LOCAL5; + return NULL; + } +#endif + +#ifdef LOG_LOCAL6 + if (!strcasecmp(val, "LOCAL6")) { + *conf = LOG_LOCAL6; + return NULL; + } +#endif + +#ifdef LOG_LOCAL7 + if (!strcasecmp(val, "LOCAL7")) { + *conf = LOG_LOCAL7; + return NULL; + } +#endif + + return "invalid value"; +} +/* }}} */ +#endif + static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); @@ -308,8 +507,10 @@ static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset) /* {{{ c->pm = PM_STYLE_STATIC; } else if (!strcasecmp(val, "dynamic")) { c->pm = PM_STYLE_DYNAMIC; + } else if (!strcasecmp(val, "ondemand")) { + c->pm = PM_STYLE_ONDEMAND; } else { - return "invalid process manager (static or dynamic)"; + return "invalid process manager (static, dynamic or ondemand)"; } return NULL; } @@ -338,7 +539,7 @@ static char *fpm_conf_set_array(zval *key, zval *value, void **config, int conve if (convert_to_bool) { char *err = fpm_conf_set_boolean(value, &subconf, 0); if (err) return err; - kv->value = strdup(b ? "On" : "Off"); + kv->value = strdup(b ? "1" : "0"); } else { kv->value = strdup(Z_STRVAL_P(value)); if (fpm_conf_expand_pool_name(&kv->value) == -1) { @@ -375,6 +576,7 @@ static void *fpm_worker_pool_config_alloc() /* {{{ */ memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s)); wp->config->listen_backlog = FPM_BACKLOG_DEFAULT; + wp->config->pm_process_idle_timeout = 10; /* 10s by default */ if (!fpm_worker_all_pools) { fpm_worker_all_pools = wp; @@ -399,13 +601,24 @@ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */ struct key_value_s *kv, *kv_next; free(wpc->name); - free(wpc->pm_status_path); - free(wpc->ping_path); - free(wpc->ping_response); + free(wpc->prefix); + free(wpc->user); + free(wpc->group); free(wpc->listen_address); free(wpc->listen_owner); free(wpc->listen_group); free(wpc->listen_mode); + free(wpc->listen_allowed_clients); + free(wpc->pm_status_path); + free(wpc->ping_path); + free(wpc->ping_response); + free(wpc->access_log); + free(wpc->access_format); + free(wpc->slowlog); + free(wpc->chroot); + free(wpc->chdir); + free(wpc->security_limit_extensions); + for (kv = wpc->php_values; kv; kv = kv_next) { kv_next = kv->next; free(kv->key); @@ -424,15 +637,6 @@ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */ free(kv->value); free(kv); } - free(wpc->listen_allowed_clients); - free(wpc->user); - free(wpc->group); - free(wpc->chroot); - free(wpc->chdir); - free(wpc->slowlog); - free(wpc->prefix); - free(wpc->access_log); - free(wpc->access_format); return 0; } @@ -503,12 +707,13 @@ static int fpm_conf_process_all_pools() /* {{{ */ struct fpm_worker_pool_s *wp; if (!fpm_worker_all_pools) { - zlog(ZLOG_ERROR, "at least one pool section must be specified in config file"); + zlog(ZLOG_ERROR, "No pool defined. at least one pool section must be specified in config file"); return -1; } for (wp = fpm_worker_all_pools; wp; wp = wp->next) { + /* prefix */ if (wp->config->prefix && *wp->config->prefix) { fpm_evaluate_full_path(&wp->config->prefix, NULL, NULL, 0); @@ -518,6 +723,13 @@ static int fpm_conf_process_all_pools() /* {{{ */ } } + /* user */ + if (!wp->config->user) { + zlog(ZLOG_ALERT, "[pool %s] user has not been defined", wp->config->name); + return -1; + } + + /* listen */ if (wp->config->listen_address && *wp->config->listen_address) { wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address); @@ -529,21 +741,19 @@ static int fpm_conf_process_all_pools() /* {{{ */ return -1; } - if (!wp->config->user) { - zlog(ZLOG_ALERT, "[pool %s] user has not been defined", wp->config->name); - return -1; - } - - if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC) { - zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static or dynamic)", wp->config->name); + /* pm */ + if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC && wp->config->pm != PM_STYLE_ONDEMAND) { + zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static, dynamic or ondemand)", wp->config->name); return -1; } + /* pm.max_children */ if (wp->config->pm_max_children < 1) { zlog(ZLOG_ALERT, "[pool %s] pm.max_children must be a positive value", wp->config->name); return -1; } + /* pm.start_servers, pm.min_spare_servers, pm.max_spare_servers */ if (wp->config->pm == PM_STYLE_DYNAMIC) { struct fpm_worker_pool_config_s *config = wp->config; @@ -559,8 +769,7 @@ static int fpm_conf_process_all_pools() /* {{{ */ if (config->pm_min_spare_servers > config->pm_max_children || config->pm_max_spare_servers > config->pm_max_children) { - zlog(ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) and pm.max_spare_servers(%d) cannot be greater than pm.max_children(%d)", - wp->config->name, config->pm_min_spare_servers, config->pm_max_spare_servers, config->pm_max_children); + zlog(ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) and pm.max_spare_servers(%d) cannot be greater than pm.max_children(%d)", wp->config->name, config->pm_min_spare_servers, config->pm_max_spare_servers, config->pm_max_children); return -1; } @@ -572,47 +781,59 @@ static int fpm_conf_process_all_pools() /* {{{ */ if (config->pm_start_servers <= 0) { config->pm_start_servers = config->pm_min_spare_servers + ((config->pm_max_spare_servers - config->pm_min_spare_servers) / 2); zlog(ZLOG_WARNING, "[pool %s] pm.start_servers is not set. It's been set to %d.", wp->config->name, config->pm_start_servers); + } else if (config->pm_start_servers < config->pm_min_spare_servers || config->pm_start_servers > config->pm_max_spare_servers) { zlog(ZLOG_ALERT, "[pool %s] pm.start_servers(%d) must not be less than pm.min_spare_servers(%d) and not greater than pm.max_spare_servers(%d)", wp->config->name, config->pm_start_servers, config->pm_min_spare_servers, config->pm_max_spare_servers); return -1; } + } else if (wp->config->pm == PM_STYLE_ONDEMAND) { + struct fpm_worker_pool_config_s *config = wp->config; - } - - if (wp->config->slowlog && *wp->config->slowlog) { - fpm_evaluate_full_path(&wp->config->slowlog, wp, NULL, 0); - } + if (!fpm_event_support_edge_trigger()) { + zlog(ZLOG_ALERT, "[pool %s] ondemand process manager can ONLY be used when events.mechanisme is either epoll (Linux) or kqueue (*BSD).", wp->config->name); + return -1; + } - if (wp->config->request_slowlog_timeout) { -#if HAVE_FPM_TRACE - if (! (wp->config->slowlog && *wp->config->slowlog)) { - zlog(ZLOG_ERROR, "[pool %s] 'slowlog' must be specified for use with 'request_slowlog_timeout'", wp->config->name); + if (config->pm_process_idle_timeout < 1) { + zlog(ZLOG_ALERT, "[pool %s] pm.process_idle_timeout(%ds) must be greater than 0s", wp->config->name, config->pm_process_idle_timeout); return -1; } -#else - static int warned = 0; - if (!warned) { - zlog(ZLOG_WARNING, "[pool %s] 'request_slowlog_timeout' is not supported on your system", wp->config->name); - warned = 1; + if (config->listen_backlog < FPM_BACKLOG_DEFAULT) { + zlog(ZLOG_WARNING, "[pool %s] listen.backlog(%d) was too low for the ondemand process manager. I updated it for you to %d.", wp->config->name, config->listen_backlog, FPM_BACKLOG_DEFAULT); + config->listen_backlog = FPM_BACKLOG_DEFAULT; } - wp->config->request_slowlog_timeout = 0; -#endif + /* certainely useless but proper */ + config->pm_start_servers = 0; + config->pm_min_spare_servers = 0; + config->pm_max_spare_servers = 0; + } - if (wp->config->slowlog && *wp->config->slowlog) { - int fd; + /* status */ + if (wp->config->pm_status_path && *wp->config->pm_status_path) { + int i; + char *status = wp->config->pm_status_path; - fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); + if (*status != '/') { + zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must start with a '/'", wp->config->name, status); + return -1; + } - if (0 > fd) { - zlog(ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog); + if (strlen(status) < 2) { + zlog(ZLOG_ERROR, "[pool %s] the status path '%s' is not long enough", wp->config->name, status); + return -1; + } + + for (i = 0; i < strlen(status); i++) { + if (!isalnum(status[i]) && status[i] != '/' && status[i] != '-' && status[i] != '_' && status[i] != '.') { + zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.'", wp->config->name, status); return -1; } - close(fd); } } + /* ping */ if (wp->config->ping_path && *wp->config->ping_path) { char *ping = wp->config->ping_path; int i; @@ -649,36 +870,62 @@ static int fpm_conf_process_all_pools() /* {{{ */ } } - if (wp->config->pm_status_path && *wp->config->pm_status_path) { - int i; - char *status = wp->config->pm_status_path; - /* struct fpm_status_s fpm_status; */ + /* access.log, access.format */ + if (wp->config->access_log && *wp->config->access_log) { + fpm_evaluate_full_path(&wp->config->access_log, wp, NULL, 0); + if (!wp->config->access_format) { + wp->config->access_format = strdup("%R - %u %t \"%m %r\" %s"); + } + } - if (*status != '/') { - zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must start with a '/'", wp->config->name, status); + if (wp->config->request_terminate_timeout) { + fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_terminate_timeout * 1000) / 3) : (wp->config->request_terminate_timeout * 1000) / 3; + } + + /* slowlog */ + if (wp->config->slowlog && *wp->config->slowlog) { + fpm_evaluate_full_path(&wp->config->slowlog, wp, NULL, 0); + } + + /* request_slowlog_timeout */ + if (wp->config->request_slowlog_timeout) { +#if HAVE_FPM_TRACE + if (! (wp->config->slowlog && *wp->config->slowlog)) { + zlog(ZLOG_ERROR, "[pool %s] 'slowlog' must be specified for use with 'request_slowlog_timeout'", wp->config->name); return -1; } +#else + static int warned = 0; - if (strlen(status) < 2) { - zlog(ZLOG_ERROR, "[pool %s] the status path '%s' is not long enough", wp->config->name, status); - return -1; + if (!warned) { + zlog(ZLOG_WARNING, "[pool %s] 'request_slowlog_timeout' is not supported on your system", wp->config->name); + warned = 1; } - for (i = 0; i < strlen(status); i++) { - if (!isalnum(status[i]) && status[i] != '/' && status[i] != '-' && status[i] != '_' && status[i] != '.') { - zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.'", wp->config->name, status); + wp->config->request_slowlog_timeout = 0; +#endif + + if (wp->config->slowlog && *wp->config->slowlog) { + int fd; + + fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); + + if (0 > fd) { + zlog(ZLOG_SYSERROR, "Unable to create or open slowlog(%s)", wp->config->slowlog); return -1; } + close(fd); } - } - if (wp->config->access_log && *wp->config->access_log) { - fpm_evaluate_full_path(&wp->config->access_log, wp, NULL, 0); - if (!wp->config->access_format) { - wp->config->access_format = strdup("%R - %u %t \"%m %r\" %s"); + fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_slowlog_timeout * 1000) / 3) : (wp->config->request_slowlog_timeout * 1000) / 3; + + if (wp->config->request_terminate_timeout && wp->config->request_slowlog_timeout > wp->config->request_terminate_timeout) { + zlog(ZLOG_ERROR, "[pool %s] 'request_slowlog_timeout' (%d) can't be greater than 'request_terminate_timeout' (%d)", wp->config->name, wp->config->request_slowlog_timeout, wp->config->request_terminate_timeout); + return -1; } } + /* chroot */ if (wp->config->chroot && *wp->config->chroot) { fpm_evaluate_full_path(&wp->config->chroot, wp, NULL, 1); @@ -687,12 +934,14 @@ static int fpm_conf_process_all_pools() /* {{{ */ zlog(ZLOG_ERROR, "[pool %s] the chroot path '%s' must start with a '/'", wp->config->name, wp->config->chroot); return -1; } + if (!fpm_conf_is_dir(wp->config->chroot)) { zlog(ZLOG_ERROR, "[pool %s] the chroot path '%s' does not exist or is not a directory", wp->config->name, wp->config->chroot); return -1; } } + /* chdir */ if (wp->config->chdir && *wp->config->chdir) { fpm_evaluate_full_path(&wp->config->chdir, wp, NULL, 0); @@ -721,6 +970,59 @@ static int fpm_conf_process_all_pools() /* {{{ */ } } } + + /* security.limit_extensions */ + if (!wp->config->security_limit_extensions) { + wp->config->security_limit_extensions = strdup(".php .phar"); + } + + if (*wp->config->security_limit_extensions) { + int nb_ext; + char *ext; + char *security_limit_extensions; + char *limit_extensions; + + + /* strdup because strtok(3) alters the string it parses */ + security_limit_extensions = strdup(wp->config->security_limit_extensions); + limit_extensions = security_limit_extensions; + nb_ext = 0; + + /* find the number of extensions */ + while ((ext = strtok(limit_extensions, " \t"))) { + limit_extensions = NULL; + nb_ext++; + } + free(security_limit_extensions); + + /* if something found */ + if (nb_ext > 0) { + + /* malloc the extension array */ + wp->limit_extensions = malloc(sizeof(char *) * (nb_ext + 1)); + if (!wp->limit_extensions) { + zlog(ZLOG_ERROR, "[pool %s] unable to malloc extensions array", wp->config->name); + return -1; + } + + /* strdup because strtok(3) alters the string it parses */ + security_limit_extensions = strdup(wp->config->security_limit_extensions); + limit_extensions = security_limit_extensions; + nb_ext = 0; + + /* parse the string and save the extension in the array */ + while ((ext = strtok(security_limit_extensions, " \t"))) { + security_limit_extensions = NULL; + wp->limit_extensions[nb_ext++] = strdup(ext); + } + + /* end the array with NULL in order to parse it */ + wp->limit_extensions[nb_ext] = NULL; + free(security_limit_extensions); + } + } + + /* env[], php_value[], php_admin_values[] */ if (!wp->config->chroot) { struct key_value_s *kv; char *options[] = FPM_PHP_INI_TO_EXPAND; @@ -750,7 +1052,7 @@ int fpm_conf_unlink_pid() /* {{{ */ { if (fpm_global_config.pid_file) { if (0 > unlink(fpm_global_config.pid_file)) { - zlog(ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file); + zlog(ZLOG_SYSERROR, "Unable to remove the PID file (%s).", fpm_global_config.pid_file); return -1; } } @@ -770,14 +1072,14 @@ int fpm_conf_write_pid() /* {{{ */ fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { - zlog(ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file); + zlog(ZLOG_SYSERROR, "Unable to create the PID file (%s).", fpm_global_config.pid_file); return -1; } len = sprintf(buf, "%d", (int) fpm_globals.parent_pid); if (len != write(fd, buf, len)) { - zlog(ZLOG_SYSERROR, "write() failed"); + zlog(ZLOG_SYSERROR, "Unable to write to the PID file."); return -1; } close(fd); @@ -794,11 +1096,31 @@ static int fpm_conf_post_process(TSRMLS_D) /* {{{ */ fpm_evaluate_full_path(&fpm_global_config.pid_file, NULL, PHP_LOCALSTATEDIR, 0); } + fpm_globals.log_level = fpm_global_config.log_level; + + if (fpm_global_config.process_max < 0) { + zlog(ZLOG_ERROR, "process_max can't be negative"); + return -1; + } + if (!fpm_global_config.error_log) { fpm_global_config.error_log = strdup("log/php-fpm.log"); } - fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0); +#ifdef HAVE_SYSLOG_H + if (!fpm_global_config.syslog_ident) { + fpm_global_config.syslog_ident = strdup("php-fpm"); + } + + if (fpm_global_config.syslog_facility < 0) { + fpm_global_config.syslog_facility = LOG_DAEMON; + } + + if (strcasecmp(fpm_global_config.error_log, "syslog") != 0) +#endif + { + fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0); + } if (0 > fpm_stdio_open_error_log(0)) { return -1; @@ -808,6 +1130,10 @@ static int fpm_conf_post_process(TSRMLS_D) /* {{{ */ return -1; } + if (0 > fpm_event_pre_init(fpm_global_config.events_mechanism)) { + return -1; + } + if (0 > fpm_conf_process_all_pools()) { return -1; } @@ -830,8 +1156,13 @@ static void fpm_conf_cleanup(int which, void *arg) /* {{{ */ { free(fpm_global_config.pid_file); free(fpm_global_config.error_log); + free(fpm_global_config.events_mechanism); fpm_global_config.pid_file = 0; fpm_global_config.error_log = 0; +#ifdef HAVE_SYSLOG_H + free(fpm_global_config.syslog_ident); + fpm_global_config.syslog_ident = 0; +#endif free(fpm_globals.config); } /* }}} */ @@ -1012,20 +1343,10 @@ static void fpm_conf_ini_parser_array(zval *name, zval *key, zval *value, void * err = fpm_conf_set_array(key, value, &config, 0); } else if (!strcmp("php_value", Z_STRVAL_P(name))) { - if (!*Z_STRVAL_P(value)) { - zlog(ZLOG_ERROR, "[%s:%d] empty value", ini_filename, ini_lineno); - *error = 1; - return; - } config = (char *)current_wp->config + WPO(php_values); err = fpm_conf_set_array(key, value, &config, 0); } else if (!strcmp("php_admin_value", Z_STRVAL_P(name))) { - if (!*Z_STRVAL_P(value)) { - zlog(ZLOG_ERROR, "[%s:%d] empty value", ini_filename, ini_lineno); - *error = 1; - return; - } config = (char *)current_wp->config + WPO(php_admin_values); err = fpm_conf_set_array(key, value, &config, 0); @@ -1088,18 +1409,18 @@ int fpm_conf_load_ini_file(char *filename TSRMLS_DC) /* {{{ */ int ret = 1; if (!filename || !filename[0]) { - zlog(ZLOG_ERROR, "Configuration file is empty"); + zlog(ZLOG_ERROR, "configuration filename is empty"); return -1; } fd = open(filename, O_RDONLY, 0); if (fd < 0) { - zlog(ZLOG_ERROR, "Unable to open file '%s', errno=%d", filename, errno); + zlog(ZLOG_SYSERROR, "failed to open configuration file '%s'", filename); return -1; } if (ini_recursion++ > 4) { - zlog(ZLOG_ERROR, "You can include more than 5 files recusively"); + zlog(ZLOG_ERROR, "failed to include more than 5 files recusively"); return -1; } @@ -1147,16 +1468,25 @@ static void fpm_conf_dump() /* {{{ */ { struct fpm_worker_pool_s *wp; + /* + * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in + */ zlog(ZLOG_NOTICE, "[General]"); zlog(ZLOG_NOTICE, "\tpid = %s", STR2STR(fpm_global_config.pid_file)); - zlog(ZLOG_NOTICE, "\tdaemonize = %s", BOOL2STR(fpm_global_config.daemonize)); zlog(ZLOG_NOTICE, "\terror_log = %s", STR2STR(fpm_global_config.error_log)); +#ifdef HAVE_SYSLOG_H + zlog(ZLOG_NOTICE, "\tsyslog.ident = %s", STR2STR(fpm_global_config.syslog_ident)); + zlog(ZLOG_NOTICE, "\tsyslog.facility = %d", fpm_global_config.syslog_facility); /* FIXME: convert to string */ +#endif zlog(ZLOG_NOTICE, "\tlog_level = %s", zlog_get_level_name(fpm_globals.log_level)); - zlog(ZLOG_NOTICE, "\tprocess_control_timeout = %ds", fpm_global_config.process_control_timeout); zlog(ZLOG_NOTICE, "\temergency_restart_interval = %ds", fpm_global_config.emergency_restart_interval); zlog(ZLOG_NOTICE, "\temergency_restart_threshold = %d", fpm_global_config.emergency_restart_threshold); + zlog(ZLOG_NOTICE, "\tprocess_control_timeout = %ds", fpm_global_config.process_control_timeout); + zlog(ZLOG_NOTICE, "\tprocess.max = %d", fpm_global_config.process_max); + zlog(ZLOG_NOTICE, "\tdaemonize = %s", BOOL2STR(fpm_global_config.daemonize)); zlog(ZLOG_NOTICE, "\trlimit_files = %d", fpm_global_config.rlimit_files); zlog(ZLOG_NOTICE, "\trlimit_core = %d", fpm_global_config.rlimit_core); + zlog(ZLOG_NOTICE, "\tevents.mechanism = %s", fpm_event_machanism_name()); zlog(ZLOG_NOTICE, " "); for (wp = fpm_worker_all_pools; wp; wp = wp->next) { @@ -1166,8 +1496,6 @@ static void fpm_conf_dump() /* {{{ */ zlog(ZLOG_NOTICE, "\tprefix = %s", STR2STR(wp->config->prefix)); zlog(ZLOG_NOTICE, "\tuser = %s", STR2STR(wp->config->user)); zlog(ZLOG_NOTICE, "\tgroup = %s", STR2STR(wp->config->group)); - zlog(ZLOG_NOTICE, "\tchroot = %s", STR2STR(wp->config->chroot)); - zlog(ZLOG_NOTICE, "\tchdir = %s", STR2STR(wp->config->chdir)); zlog(ZLOG_NOTICE, "\tlisten = %s", STR2STR(wp->config->listen_address)); zlog(ZLOG_NOTICE, "\tlisten.backlog = %d", wp->config->listen_backlog); zlog(ZLOG_NOTICE, "\tlisten.owner = %s", STR2STR(wp->config->listen_owner)); @@ -1176,21 +1504,25 @@ static void fpm_conf_dump() /* {{{ */ zlog(ZLOG_NOTICE, "\tlisten.allowed_clients = %s", STR2STR(wp->config->listen_allowed_clients)); zlog(ZLOG_NOTICE, "\tpm = %s", PM2STR(wp->config->pm)); zlog(ZLOG_NOTICE, "\tpm.max_children = %d", wp->config->pm_max_children); - zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests); zlog(ZLOG_NOTICE, "\tpm.start_servers = %d", wp->config->pm_start_servers); zlog(ZLOG_NOTICE, "\tpm.min_spare_servers = %d", wp->config->pm_min_spare_servers); zlog(ZLOG_NOTICE, "\tpm.max_spare_servers = %d", wp->config->pm_max_spare_servers); + zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d", wp->config->pm_process_idle_timeout); + zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests); zlog(ZLOG_NOTICE, "\tpm.status_path = %s", STR2STR(wp->config->pm_status_path)); zlog(ZLOG_NOTICE, "\tping.path = %s", STR2STR(wp->config->ping_path)); zlog(ZLOG_NOTICE, "\tping.response = %s", STR2STR(wp->config->ping_response)); zlog(ZLOG_NOTICE, "\taccess.log = %s", STR2STR(wp->config->access_log)); zlog(ZLOG_NOTICE, "\taccess.format = %s", STR2STR(wp->config->access_format)); - zlog(ZLOG_NOTICE, "\tcatch_workers_output = %s", BOOL2STR(wp->config->catch_workers_output)); - zlog(ZLOG_NOTICE, "\trequest_terminate_timeout = %ds", wp->config->request_terminate_timeout); - zlog(ZLOG_NOTICE, "\trequest_slowlog_timeout = %ds", wp->config->request_slowlog_timeout); zlog(ZLOG_NOTICE, "\tslowlog = %s", STR2STR(wp->config->slowlog)); + zlog(ZLOG_NOTICE, "\trequest_slowlog_timeout = %ds", wp->config->request_slowlog_timeout); + zlog(ZLOG_NOTICE, "\trequest_terminate_timeout = %ds", wp->config->request_terminate_timeout); zlog(ZLOG_NOTICE, "\trlimit_files = %d", wp->config->rlimit_files); zlog(ZLOG_NOTICE, "\trlimit_core = %d", wp->config->rlimit_core); + zlog(ZLOG_NOTICE, "\tchroot = %s", STR2STR(wp->config->chroot)); + zlog(ZLOG_NOTICE, "\tchdir = %s", STR2STR(wp->config->chdir)); + zlog(ZLOG_NOTICE, "\tcatch_workers_output = %s", BOOL2STR(wp->config->catch_workers_output)); + zlog(ZLOG_NOTICE, "\tsecurity.limit_extensions = %s", wp->config->security_limit_extensions); for (kv = wp->config->env; kv; kv = kv->next) { zlog(ZLOG_NOTICE, "\tenv[%s] = %s", kv->key, kv->value); diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h index 2152527ee..9fbd5064c 100644 --- a/sapi/fpm/fpm/fpm_conf.h +++ b/sapi/fpm/fpm/fpm_conf.h @@ -8,6 +8,8 @@ #include <stdint.h> #include "php.h" +#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : (a == PM_STYLE_DYNAMIC ? "dynamic" : "ondemand")) + #define FPM_CONF_MAX_PONG_LENGTH 64 struct key_value_s; @@ -18,49 +20,64 @@ struct key_value_s { char *value; }; +/* + * Please keep the same order as in fpm_conf.c and in php-fpm.conf.in + */ struct fpm_global_config_s { + char *pid_file; + char *error_log; +#ifdef HAVE_SYSLOG_H + char *syslog_ident; + int syslog_facility; +#endif + int log_level; int emergency_restart_threshold; int emergency_restart_interval; int process_control_timeout; + int process_max; int daemonize; - char *pid_file; - char *error_log; int rlimit_files; int rlimit_core; + char *events_mechanism; }; extern struct fpm_global_config_s fpm_global_config; +/* + * Please keep the same order as in fpm_conf.c and in php-fpm.conf.in + */ struct fpm_worker_pool_config_s { char *name; char *prefix; char *user; char *group; - char *chroot; - char *chdir; - int request_terminate_timeout; - int request_slowlog_timeout; - char *slowlog; - int rlimit_files; - int rlimit_core; - int catch_workers_output; + char *listen_address; + int listen_backlog; + char *listen_owner; + char *listen_group; + char *listen_mode; + char *listen_allowed_clients; int pm; int pm_max_children; - char *pm_status_path; - int pm_max_requests; int pm_start_servers; int pm_min_spare_servers; int pm_max_spare_servers; + int pm_process_idle_timeout; + int pm_max_requests; + char *pm_status_path; char *ping_path; char *ping_response; char *access_log; char *access_format; - char *listen_address; - int listen_backlog; - char *listen_owner; - char *listen_group; - char *listen_mode; - char *listen_allowed_clients; + char *slowlog; + int request_slowlog_timeout; + int request_terminate_timeout; + int rlimit_files; + int rlimit_core; + char *chroot; + char *chdir; + int catch_workers_output; + char *security_limit_extensions; struct key_value_s *env; struct key_value_s *php_admin_values; struct key_value_s *php_values; @@ -74,7 +91,8 @@ struct ini_value_parser_s { enum { PM_STYLE_STATIC = 1, - PM_STYLE_DYNAMIC = 2 + PM_STYLE_DYNAMIC = 2, + PM_STYLE_ONDEMAND = 3 }; int fpm_conf_init_main(int test_conf); diff --git a/sapi/fpm/fpm/fpm_env.c b/sapi/fpm/fpm/fpm_env.c index 03bf82340..6b64fedfe 100644 --- a/sapi/fpm/fpm/fpm_env.c +++ b/sapi/fpm/fpm/fpm_env.c @@ -13,7 +13,6 @@ #include "fpm_env.h" #include "fpm.h" -#include "zlog.h" #ifndef HAVE_SETPROCTITLE #ifdef __linux__ diff --git a/sapi/fpm/fpm/fpm_events.c b/sapi/fpm/fpm/fpm_events.c index 8ae9ad2e2..d5f7483b4 100644 --- a/sapi/fpm/fpm/fpm_events.c +++ b/sapi/fpm/fpm/fpm_events.c @@ -10,7 +10,6 @@ #include <string.h> #include <php.h> -#include <php_network.h> #include "fpm.h" #include "fpm_process_ctl.h" @@ -23,13 +22,14 @@ #include "fpm_clock.h" #include "fpm_log.h" -#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout); +#include "events/select.h" +#include "events/poll.h" +#include "events/epoll.h" +#include "events/devpoll.h" +#include "events/port.h" +#include "events/kqueue.h" -typedef struct fpm_event_queue_s { - struct fpm_event_queue_s *prev; - struct fpm_event_queue_s *next; - struct fpm_event_s *ev; -} fpm_event_queue; +#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout); static void fpm_event_cleanup(int which, void *arg); static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg); @@ -38,16 +38,12 @@ static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_even static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev); static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue); -static int fpm_event_nfds_max; +static struct fpm_event_module_s *module; static struct fpm_event_queue_s *fpm_event_queue_timer = NULL; static struct fpm_event_queue_s *fpm_event_queue_fd = NULL; -static php_pollfd *fpm_event_ufds = NULL; static void fpm_event_cleanup(int which, void *arg) /* {{{ */ { - if (fpm_event_ufds) { - free(fpm_event_ufds); - } fpm_event_queue_destroy(&fpm_event_queue_timer); fpm_event_queue_destroy(&fpm_event_queue_fd); } @@ -66,7 +62,7 @@ static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg) /* {{ if (res <= 0) { if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - zlog(ZLOG_SYSERROR, "read() failed"); + zlog(ZLOG_SYSERROR, "unable to read from the signal pipe"); } return; } @@ -153,7 +149,7 @@ static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_even } if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) { - zlog(ZLOG_SYSERROR, "malloc() failed"); + zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed"); return -1; } elt->prev = NULL; @@ -166,6 +162,11 @@ static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_even } *queue = elt; + /* ask the event module to add the fd from its own queue */ + if (*queue == fpm_event_queue_fd && module->add) { + module->add(ev); + } + return 0; } /* }}} */ @@ -189,6 +190,12 @@ static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_even *queue = q->next; (*queue)->prev = NULL; } + + /* ask the event module to remove the fd from its own queue */ + if (*queue == fpm_event_queue_fd && module->remove) { + module->remove(ev); + } + free(q); return 0; } @@ -205,6 +212,11 @@ static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */ if (!queue) { return; } + + if (*queue == fpm_event_queue_fd && module->clean) { + module->clean(); + } + q = *queue; while (q) { tmp = q; @@ -216,27 +228,107 @@ static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */ } /* }}} */ +int fpm_event_pre_init(char *machanism) /* {{{ */ +{ + /* kqueue */ + module = fpm_event_kqueue_module(); + if (module) { + if (!machanism || strcasecmp(module->name, machanism) == 0) { + return 0; + } + } + + /* port */ + module = fpm_event_port_module(); + if (module) { + if (!machanism || strcasecmp(module->name, machanism) == 0) { + return 0; + } + } + + /* epoll */ + module = fpm_event_epoll_module(); + if (module) { + if (!machanism || strcasecmp(module->name, machanism) == 0) { + return 0; + } + } + + /* /dev/poll */ + module = fpm_event_devpoll_module(); + if (module) { + if (!machanism || strcasecmp(module->name, machanism) == 0) { + return 0; + } + } + + /* poll */ + module = fpm_event_poll_module(); + if (module) { + if (!machanism || strcasecmp(module->name, machanism) == 0) { + return 0; + } + } + + /* select */ + module = fpm_event_select_module(); + if (module) { + if (!machanism || strcasecmp(module->name, machanism) == 0) { + return 0; + } + } + + if (machanism) { + zlog(ZLOG_ERROR, "event mechanism '%s' is not available on this system", machanism); + } else { + zlog(ZLOG_ERROR, "unable to find a suitable event mechanism on this system"); + } + return -1; +} +/* }} */ + +const char *fpm_event_machanism_name() /* {{{ */ +{ + return module ? module->name : NULL; +} +/* }}} */ + +int fpm_event_support_edge_trigger() /* {{{ */ +{ + return module ? module->support_edge_trigger : 0; +} +/* }}} */ + int fpm_event_init_main() /* {{{ */ { struct fpm_worker_pool_s *wp; + int max; + + if (!module) { + zlog(ZLOG_ERROR, "no event module found"); + return -1; + } + + if (!module->wait) { + zlog(ZLOG_ERROR, "Incomplete event implementation. Please open a bug report on https://bugs.php.net."); + return -1; + } /* count the max number of necessary fds for polling */ - fpm_event_nfds_max = 1; /* only one FD is necessary at startup for the master process signal pipe */ + max = 1; /* only one FD is necessary at startup for the master process signal pipe */ for (wp = fpm_worker_all_pools; wp; wp = wp->next) { if (!wp->config) continue; if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) { - fpm_event_nfds_max += (wp->config->pm_max_children * 2); + max += (wp->config->pm_max_children * 2); } } - /* malloc the max number of necessary fds for polling */ - fpm_event_ufds = malloc(sizeof(php_pollfd) * fpm_event_nfds_max); - if (!fpm_event_ufds) { - zlog(ZLOG_SYSERROR, "malloc() failed"); + if (module->init(max) < 0) { + zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name); return -1; } - zlog(ZLOG_DEBUG, "%d fds have been reserved", fpm_event_nfds_max); + zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max); if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) { return -1; @@ -258,7 +350,9 @@ void fpm_event_loop(int err) /* {{{ */ fpm_event_add(&signal_fd_event, 0); /* add timers */ - fpm_pctl_heartbeat(NULL, 0, NULL); + if (fpm_globals.heartbeat > 0) { + fpm_pctl_heartbeat(NULL, 0, NULL); + } if (!err) { fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL); @@ -273,7 +367,7 @@ void fpm_event_loop(int err) /* {{{ */ struct timeval tmp; struct timeval now; unsigned long int timeout; - int i, ret; + int ret; /* sanity check */ if (fpm_globals.parent_pid != getpid()) { @@ -304,41 +398,15 @@ void fpm_event_loop(int err) /* {{{ */ timeout = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000) + 1; } - /* init fpm_event_ufds for php_poll2 */ - memset(fpm_event_ufds, 0, sizeof(php_pollfd) * fpm_event_nfds_max); - i = 0; - q = fpm_event_queue_fd; - while (q && i < fpm_event_nfds_max) { - fpm_event_ufds[i].fd = q->ev->fd; - fpm_event_ufds[i].events = POLLIN; - q->ev->index = i++; - q = q->next; + ret = module->wait(fpm_event_queue_fd, timeout); + + /* is a child, nothing to do here */ + if (ret == -2) { + return; } - /* wait for inconming event or timeout */ - if ((ret = php_poll2(fpm_event_ufds, i, timeout)) == -1) { - if (errno != EINTR) { - zlog(ZLOG_WARNING, "php_poll2() returns %d", errno); - } - } else if (ret > 0) { - - /* trigger POLLIN events */ - q = fpm_event_queue_fd; - while (q) { - if (q->ev && q->ev->index >= 0 && q->ev->index < fpm_event_nfds_max) { - if (q->ev->fd == fpm_event_ufds[q->ev->index].fd) { - if (fpm_event_ufds[q->ev->index].revents & POLLIN) { - fpm_event_fire(q->ev); - /* sanity check */ - if (fpm_globals.parent_pid != getpid()) { - return; - } - } - } - q->ev->index = -1; - } - q = q->next; - } + if (ret > 0) { + zlog(ZLOG_DEBUG, "event module triggered %d events", ret); } /* trigger timers */ @@ -446,11 +514,11 @@ int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */ int fpm_event_del(struct fpm_event_s *ev) /* {{{ */ { - if (fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) { + if (ev->index >= 0 && fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) { return -1; } - if (fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) { + if (ev->index < 0 && fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) { return -1; } diff --git a/sapi/fpm/fpm/fpm_events.h b/sapi/fpm/fpm/fpm_events.h index 586b24283..416ec6e72 100644 --- a/sapi/fpm/fpm/fpm_events.h +++ b/sapi/fpm/fpm/fpm_events.h @@ -8,6 +8,7 @@ #define FPM_EV_TIMEOUT (1 << 0) #define FPM_EV_READ (1 << 1) #define FPM_EV_PERSIST (1 << 2) +#define FPM_EV_EDGE (1 << 3) #define fpm_event_set_timer(ev, flags, cb, arg) fpm_event_set((ev), -1, (flags), (cb), (arg)) @@ -22,11 +23,30 @@ struct fpm_event_s { short which; /* type of event */ }; +typedef struct fpm_event_queue_s { + struct fpm_event_queue_s *prev; + struct fpm_event_queue_s *next; + struct fpm_event_s *ev; +} fpm_event_queue; + +struct fpm_event_module_s { + const char *name; + int support_edge_trigger; + int (*init)(int max_fd); + int (*clean)(void); + int (*wait)(struct fpm_event_queue_s *queue, unsigned long int timeout); + int (*add)(struct fpm_event_s *ev); + int (*remove)(struct fpm_event_s *ev); +}; + void fpm_event_loop(int err); void fpm_event_fire(struct fpm_event_s *ev); int fpm_event_init_main(); int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg); int fpm_event_add(struct fpm_event_s *ev, unsigned long int timeout); int fpm_event_del(struct fpm_event_s *ev); +int fpm_event_pre_init(char *machanism); +const char *fpm_event_machanism_name(); +int fpm_event_support_edge_trigger(); #endif diff --git a/sapi/fpm/fpm/fpm_log.c b/sapi/fpm/fpm/fpm_log.c index ef1c0c3be..69bd31b11 100644 --- a/sapi/fpm/fpm/fpm_log.c +++ b/sapi/fpm/fpm/fpm_log.c @@ -29,9 +29,6 @@ static char *fpm_log_format = NULL; static int fpm_log_fd = -1; -#ifdef HAVE_TIMES -static float tick; -#endif int fpm_log_open(int reopen) /* {{{ */ { @@ -47,7 +44,7 @@ int fpm_log_open(int reopen) /* {{{ */ fd = open(wp->config->access_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (0 > fd) { - zlog(ZLOG_SYSERROR, "open(\"%s\") failed", wp->config->access_log); + zlog(ZLOG_SYSERROR, "failed to open access log (%s)", wp->config->access_log); return -1; } @@ -67,24 +64,6 @@ int fpm_log_open(int reopen) /* {{{ */ } /* }}} */ -int fpm_log_init_main() /* {{{ */ -{ -#ifdef HAVE_TIMES -#if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)) - tick = sysconf(_SC_CLK_TCK); -#else /* _SC_CLK_TCK */ -#ifdef HZ - tick = HZ; -#else /* HZ */ - tick = 100; -#endif /* HZ */ -#endif /* _SC_CLK_TCK */ - zlog(ZLOG_DEBUG, "got clock tick '%.0f'", tick); -#endif /* HAVE_TIMES */ - return 0; -} -/* }}} */ - /* }}} */ int fpm_log_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ { @@ -122,7 +101,6 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */ size_t len, len2; struct fpm_scoreboard_proc_s proc, *proc_p; struct fpm_scoreboard_s *scoreboard; - struct timeval uptime, now; char tmp[129]; char format[129]; time_t now_epoch; @@ -141,24 +119,21 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */ test = 1; } - fpm_clock_get(&now); now_epoch = time(NULL); if (!test) { scoreboard = fpm_scoreboard_get(); if (!scoreboard) { - zlog(ZLOG_WARNING, "unable to get scoreboard"); + zlog(ZLOG_WARNING, "unable to get scoreboard while preparing the access log"); return -1; } proc_p = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (!proc_p) { - zlog(ZLOG_WARNING, "[pool %s] Unable to acquire shm slot", scoreboard->pool); + zlog(ZLOG_WARNING, "[pool %s] Unable to acquire shm slot while preparing the access log", scoreboard->pool); return -1; } proc = *proc_p; fpm_scoreboard_proc_release(proc_p); - - timersub(&now, &proc.accepted, &uptime); } token = 0; @@ -172,7 +147,7 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */ while (*s != '\0') { if (len > FPM_LOG_BUFFER) { - zlog(ZLOG_NOTICE, "the log buffer is full (%d). The log request has been truncated.", FPM_LOG_BUFFER); + zlog(ZLOG_NOTICE, "the log buffer is full (%d). The access log request has been truncated.", FPM_LOG_BUFFER); len = FPM_LOG_BUFFER - 1; break; } @@ -198,19 +173,15 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */ case 'C': /* %CPU */ if (format[0] == '\0' || !strcasecmp(format, "total")) { if (!test) { - tms_total = - (proc.cpu_finished.tms_utime + proc.cpu_finished.tms_stime + proc.cpu_finished.tms_cutime + proc.cpu_finished.tms_cstime) - - - (proc.cpu_accepted.tms_utime + proc.cpu_accepted.tms_stime + proc.cpu_accepted.tms_cutime + proc.cpu_accepted.tms_cstime) - ; + tms_total = proc.last_request_cpu.tms_utime + proc.last_request_cpu.tms_stime + proc.last_request_cpu.tms_cutime + proc.last_request_cpu.tms_cstime; } } else if (!strcasecmp(format, "user")) { if (!test) { - tms_total = (proc.cpu_finished.tms_utime + proc.cpu_finished.tms_cutime) - (proc.cpu_accepted.tms_utime + proc.cpu_accepted.tms_cutime); + tms_total = proc.last_request_cpu.tms_utime + proc.last_request_cpu.tms_cutime; } } else if (!strcasecmp(format, "system")) { if (!test) { - tms_total = (proc.cpu_finished.tms_stime + proc.cpu_finished.tms_cstime) - (proc.cpu_accepted.tms_stime + proc.cpu_accepted.tms_cstime); + tms_total = proc.last_request_cpu.tms_stime + proc.last_request_cpu.tms_cstime; } } else { zlog(ZLOG_WARNING, "only 'total', 'user' or 'system' are allowed as a modifier for %%%c ('%s')", *s, format); @@ -219,7 +190,7 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */ format[0] = '\0'; if (!test) { - len2 = snprintf(b, FPM_LOG_BUFFER - len, "%.2f", tms_total / tick / (proc.cpu_duration.tv_sec + proc.cpu_duration.tv_usec / 1000000.) * 100.); + len2 = snprintf(b, FPM_LOG_BUFFER - len, "%.2f", tms_total / fpm_scoreboard_get_tick() / (proc.cpu_duration.tv_sec + proc.cpu_duration.tv_usec / 1000000.) * 100.); } break; #endif @@ -228,19 +199,19 @@ int fpm_log_write(char *log_format TSRMLS_DC) /* {{{ */ /* seconds */ if (format[0] == '\0' || !strcasecmp(format, "seconds")) { if (!test) { - len2 = snprintf(b, FPM_LOG_BUFFER - len, "%.3f", uptime.tv_sec + uptime.tv_usec / 1000000.); + len2 = snprintf(b, FPM_LOG_BUFFER - len, "%.3f", proc.duration.tv_sec + proc.duration.tv_usec / 1000000.); } /* miliseconds */ } else if (!strcasecmp(format, "miliseconds") || !strcasecmp(format, "mili")) { if (!test) { - len2 = snprintf(b, FPM_LOG_BUFFER - len, "%.3f", uptime.tv_sec * 1000. + uptime.tv_usec / 1000.); + len2 = snprintf(b, FPM_LOG_BUFFER - len, "%.3f", proc.duration.tv_sec * 1000. + proc.duration.tv_usec / 1000.); } /* microseconds */ } else if (!strcasecmp(format, "microseconds") || !strcasecmp(format, "micro")) { if (!test) { - len2 = snprintf(b, FPM_LOG_BUFFER - len, "%lu", uptime.tv_sec * 1000000UL + uptime.tv_usec); + len2 = snprintf(b, FPM_LOG_BUFFER - len, "%lu", proc.duration.tv_sec * 1000000UL + proc.duration.tv_usec); } } else { diff --git a/sapi/fpm/fpm/fpm_log.h b/sapi/fpm/fpm/fpm_log.h index 74f842646..f0199d9cb 100644 --- a/sapi/fpm/fpm/fpm_log.h +++ b/sapi/fpm/fpm/fpm_log.h @@ -6,7 +6,6 @@ #define FPM_LOG_H 1 #include "fpm_worker_pool.h" -int fpm_log_init_main(); int fpm_log_init_child(struct fpm_worker_pool_s *wp); int fpm_log_write(char *log_format TSRMLS_DC); int fpm_log_open(int reopen); diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index c2db60f11..ea0dd149f 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -100,12 +100,13 @@ int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS; #include "fastcgi.h" #include <php_config.h> -#include <fpm/fpm.h> -#include <fpm/fpm_request.h> -#include <fpm/fpm_status.h> -#include <fpm/fpm_conf.h> -#include <fpm/fpm_php.h> -#include <fpm/fpm_log.h> +#include "fpm.h" +#include "fpm_request.h" +#include "fpm_status.h" +#include "fpm_conf.h" +#include "fpm_php.h" +#include "fpm_log.h" +#include "zlog.h" #ifndef PHP_WIN32 /* XXX this will need to change later when threaded fastcgi is implemented. shane */ @@ -124,6 +125,7 @@ static int parent = 1; #endif static int request_body_fd; +static int fpm_is_running = 0; static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC); static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC); @@ -260,34 +262,33 @@ static void print_extensions(TSRMLS_D) zend_llist_destroy(&sorted_exts); } -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 #endif static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC) { -#ifdef PHP_WRITE_STDOUT - long ret; -#else - size_t ret; -#endif + ssize_t ret; - if (fcgi_is_fastcgi()) { + /* sapi has started which means everyhting must be send through fcgi */ + if (fpm_is_running) { fcgi_request *request = (fcgi_request*) SG(server_context); - long ret = fcgi_write(request, FCGI_STDOUT, str, str_length); + ret = fcgi_write(request, FCGI_STDOUT, str, str_length); if (ret <= 0) { return 0; } - return ret; + return (size_t)ret; } -#ifdef PHP_WRITE_STDOUT - ret = write(STDOUT_FILENO, str, str_length); - if (ret <= 0) return 0; - return ret; + /* sapi has not started, output to stdout instead of fcgi */ +#ifdef PHP_WRITE_STDOUT + ret = write(STDOUT_FILENO, str, str_length); + if (ret <= 0) { + return 0; + } + return (size_t)ret; #else - ret = fwrite(str, 1, MIN(str_length, 16384), stdout); - return ret; + return fwrite(str, 1, MIN(str_length, 16384), stdout); #endif } @@ -313,17 +314,20 @@ static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC) static void sapi_cgibin_flush(void *server_context) { - if (fcgi_is_fastcgi()) { + /* fpm has started, let use fcgi instead of stdout */ + if (fpm_is_running) { fcgi_request *request = (fcgi_request*) server_context; if ( #ifndef PHP_WIN32 - !parent && + !parent && #endif - request && !fcgi_flush(request, 0)) { + request && !fcgi_flush(request, 0)) { php_handle_aborted_connection(); } return; } + + /* fpm has not started yet, let use stdout instead of fcgi */ if (fflush(stdout) == EOF) { php_handle_aborted_connection(); } @@ -490,31 +494,27 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC) count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes)); while (read_bytes < count_bytes) { - if (fcgi_is_fastcgi()) { - fcgi_request *request = (fcgi_request*) SG(server_context); - if (request_body_fd == -1) { - char *request_body_filename = sapi_cgibin_getenv((char *) "REQUEST_BODY_FILE", - sizeof("REQUEST_BODY_FILE") - 1 TSRMLS_CC); - - if (request_body_filename && *request_body_filename) { - request_body_fd = open(request_body_filename, O_RDONLY); - - if (0 > request_body_fd) { - php_error(E_WARNING, "REQUEST_BODY_FILE: open('%s') failed: %s (%d)", - request_body_filename, strerror(errno), errno); - return 0; - } + fcgi_request *request = (fcgi_request*) SG(server_context); + if (request_body_fd == -1) { + char *request_body_filename = sapi_cgibin_getenv((char *) "REQUEST_BODY_FILE", + sizeof("REQUEST_BODY_FILE") - 1 TSRMLS_CC); + + if (request_body_filename && *request_body_filename) { + request_body_fd = open(request_body_filename, O_RDONLY); + + if (0 > request_body_fd) { + php_error(E_WARNING, "REQUEST_BODY_FILE: open('%s') failed: %s (%d)", + request_body_filename, strerror(errno), errno); + return 0; } } + } - /* If REQUEST_BODY_FILE variable not available - read post body from fastcgi stream */ - if (request_body_fd < 0) { - tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes); - } else { - tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes); - } + /* If REQUEST_BODY_FILE variable not available - read post body from fastcgi stream */ + if (request_body_fd < 0) { + tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes); } else { - tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes); + tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes); } if (tmp_read_bytes <= 0) { break; @@ -526,77 +526,27 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC) static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC) { - /* when php is started by mod_fastcgi, no regular environment - * is provided to PHP. It is always sent to PHP at the start - * of a request. So we have to do our own lookup to get env - * vars. This could probably be faster somehow. */ - if (fcgi_is_fastcgi()) { + /* if fpm has started, use fcgi env */ + if (fpm_is_running) { fcgi_request *request = (fcgi_request*) SG(server_context); return fcgi_getenv(request, name, name_len); } - /* if cgi, or fastcgi and not found in fcgi env - check the regular environment */ + + /* if fpm has not started yet, use std env */ return getenv(name); } static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC) { int name_len; -#if !HAVE_SETENV || !HAVE_UNSETENV - int len; - char *buf; -#endif if (!name) { return NULL; } name_len = strlen(name); - /* when php is started by mod_fastcgi, no regular environment - * is provided to PHP. It is always sent to PHP at the start - * of a request. So we have to do our own lookup to get env - * vars. This could probably be faster somehow. */ - if (fcgi_is_fastcgi()) { - fcgi_request *request = (fcgi_request*) SG(server_context); - return fcgi_putenv(request, name, name_len, value); - } - -#if HAVE_SETENV - if (value) { - setenv(name, value, 1); - } -#endif -#if HAVE_UNSETENV - if (!value) { - unsetenv(name); - } -#endif - -#if !HAVE_SETENV || !HAVE_UNSETENV - /* if cgi, or fastcgi and not found in fcgi env - check the regular environment - this leaks, but it's only cgi anyway, we'll fix - it for 5.0 - */ - len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2; - buf = (char *) malloc(len); - if (buf == NULL) { - return getenv(name); - } -#endif -#if !HAVE_SETENV - if (value) { - len = slprintf(buf, len - 1, "%s=%s", name, value); - putenv(buf); - } -#endif -#if !HAVE_UNSETENV - if (!value) { - len = slprintf(buf, len - 1, "%s=", name); - putenv(buf); - } -#endif - return getenv(name); + fcgi_request *request = (fcgi_request*) SG(server_context); + return fcgi_putenv(request, name, name_len, value); } static char *sapi_cgi_read_cookies(TSRMLS_D) @@ -606,6 +556,15 @@ static char *sapi_cgi_read_cookies(TSRMLS_D) void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC) { + fcgi_request *request; + HashPosition pos; + int magic_quotes_gpc;; + char *var, **val; + uint var_len; + ulong idx; + int filter_arg; + + if (PG(http_globals)[TRACK_VARS_ENV] && array_ptr != PG(http_globals)[TRACK_VARS_ENV] && Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY && @@ -631,30 +590,24 @@ void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC) /* call php's original import as a catch-all */ php_php_import_environment_variables(array_ptr TSRMLS_CC); - if (fcgi_is_fastcgi()) { - fcgi_request *request = (fcgi_request*) SG(server_context); - HashPosition pos; - int magic_quotes_gpc = PG(magic_quotes_gpc); - char *var, **val; - uint var_len; - ulong idx; - int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER; - - /* turn off magic_quotes while importing environment variables */ - PG(magic_quotes_gpc) = 0; - for (zend_hash_internal_pointer_reset_ex(request->env, &pos); - zend_hash_get_current_key_ex(request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING && - zend_hash_get_current_data_ex(request->env, (void **) &val, &pos) == SUCCESS; - zend_hash_move_forward_ex(request->env, &pos) - ) { - unsigned int new_val_len; + request = (fcgi_request*) SG(server_context); + magic_quotes_gpc = PG(magic_quotes_gpc); + filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER; - if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) { - php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC); - } + /* turn off magic_quotes while importing environment variables */ + PG(magic_quotes_gpc) = 0; + for (zend_hash_internal_pointer_reset_ex(request->env, &pos); + zend_hash_get_current_key_ex(request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING && + zend_hash_get_current_data_ex(request->env, (void **) &val, &pos) == SUCCESS; + zend_hash_move_forward_ex(request->env, &pos) + ) { + unsigned int new_val_len; + + if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) { + php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC); } - PG(magic_quotes_gpc) = magic_quotes_gpc; } + PG(magic_quotes_gpc) = magic_quotes_gpc; } static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC) @@ -702,24 +655,8 @@ static void sapi_cgi_log_message(char *message) { TSRMLS_FETCH(); - if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) { - fcgi_request *request; - - request = (fcgi_request*) SG(server_context); - if (request) { - int len = strlen(message); - char *buf = malloc(len+2); - - memcpy(buf, message, len); - memcpy(buf + len, "\n", sizeof("\n")); - fcgi_write(request, FCGI_STDERR, buf, len+1); - free(buf); - } else { - fprintf(stderr, "%s\n", message); - } - /* ignore return code */ - } else { - fprintf(stderr, "%s\n", message); + if (CGIG(fcgi_logging)) { + zlog(ZLOG_NOTICE, "PHP message: %s", message); } } @@ -877,16 +814,12 @@ static int sapi_cgi_deactivate(TSRMLS_D) 2. When the first call occurs and the request is not set up, flush fails on FastCGI. */ if (SG(sapi_started)) { - if (fcgi_is_fastcgi()) { - if ( + if ( #ifndef PHP_WIN32 - !parent && + !parent && #endif - !fcgi_finish_request((fcgi_request*)SG(server_context), 0)) { - php_handle_aborted_connection(); - } - } else { - sapi_cgibin_flush(SG(server_context)); + !fcgi_finish_request((fcgi_request*)SG(server_context), 0)) { + php_handle_aborted_connection(); } } return SUCCESS; @@ -1399,7 +1332,7 @@ static void init_request_info(TSRMLS_D) /* FIXME - Work out proto_num here */ SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING") - 1 TSRMLS_CC); SG(request_info).content_type = (content_type ? content_type : "" ); - SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + SG(request_info).content_length = (content_length ? atol(content_length) : 0); /* The CGI RFC allows servers to pass on unvalidated Authorization data */ auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION") - 1 TSRMLS_CC); @@ -1437,14 +1370,14 @@ static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_ if (!mode || !arg1) return; if (callback_type != ZEND_INI_PARSER_ENTRY) { - fprintf(stderr, "Passing INI directive through FastCGI: only classic entries are allowed\n"); + zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: only classic entries are allowed"); return; } key = Z_STRVAL_P(arg1); if (!key || strlen(key) < 1) { - fprintf(stderr, "Passing INI directive through FastCGI: empty key\n"); + zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: empty key"); return; } @@ -1453,7 +1386,7 @@ static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_ } if (!value) { - fprintf(stderr, "Passing INI directive through FastCGI: empty value for key '%s'\n", key); + zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: empty value for key '%s'", key); return; } @@ -1461,7 +1394,7 @@ static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_ kv.value = value; kv.next = NULL; if (fpm_php_apply_defines_ex(&kv, *mode) == -1) { - fprintf(stderr, "Passing INI directive through FastCGI: unable to set '%s'\n", key); + zlog(ZLOG_ERROR, "Passing INI directive through FastCGI: unable to set '%s'", key); } } /* }}} */ @@ -1536,7 +1469,7 @@ PHP_FUNCTION(fastcgi_finish_request) /* {{{ */ { fcgi_request *request = (fcgi_request*) SG(server_context); - if (fcgi_is_fastcgi() && request->fd >= 0) { + if (request->fd >= 0) { php_end_ob_buffers(1 TSRMLS_CC); php_header(TSRMLS_C); @@ -1595,6 +1528,7 @@ int main(int argc, char *argv[]) char *fpm_prefix = NULL; char *fpm_pid = NULL; int test_conf = 0; + int php_information = 0; fcgi_init(); @@ -1705,20 +1639,8 @@ int main(int argc, char *argv[]) goto out; case 'i': /* php info & quit */ - cgi_sapi_module.phpinfo_as_text = 1; - cgi_sapi_module.startup(&cgi_sapi_module); - if (php_request_startup(TSRMLS_C) == FAILURE) { - SG(server_context) = NULL; - php_module_shutdown(TSRMLS_C); - return FAILURE; - } - SG(headers_sent) = 1; - SG(request_info).no_headers = 1; - php_print_info(0xFFFFFFFF TSRMLS_CC); - php_request_shutdown((void *) 0); - fcgi_shutdown(); - exit_status = 0; - goto out; + php_information = 1; + break; default: case 'h': @@ -1755,6 +1677,23 @@ int main(int argc, char *argv[]) } } + if (php_information) { + cgi_sapi_module.phpinfo_as_text = 1; + cgi_sapi_module.startup(&cgi_sapi_module); + if (php_request_startup(TSRMLS_C) == FAILURE) { + SG(server_context) = NULL; + php_module_shutdown(TSRMLS_C); + return FAILURE; + } + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + php_print_info(0xFFFFFFFF TSRMLS_CC); + php_request_shutdown((void *) 0); + fcgi_shutdown(); + exit_status = 0; + goto out; + } + /* No other args are permitted here as there is not interactive mode */ if (argc != php_optind) { cgi_sapi_module.startup(&cgi_sapi_module); @@ -1830,9 +1769,10 @@ consult the installation file that came with this distribution, or visit \n\ return FAILURE; } + fpm_is_running = 1; + fcgi_fd = fpm_run(&max_requests); parent = 0; - fcgi_set_is_fastcgi(1); /* make php call us to get _ENV vars */ php_php_import_environment_variables = php_import_environment_variables; @@ -1847,6 +1787,7 @@ consult the installation file that came with this distribution, or visit \n\ SG(server_context) = (void *) &request; init_request_info(TSRMLS_C); CG(interactive) = 0; + char *primary_script = NULL; fpm_request_info(); @@ -1872,15 +1813,30 @@ consult the installation file that came with this distribution, or visit \n\ /* If path_translated is NULL, terminate here with a 404 */ if (!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 (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 (php_fopen_primary_script(&file_handle TSRMLS_CC) == 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"); @@ -1902,6 +1858,10 @@ consult the installation file that came with this distribution, or visit \n\ php_execute_script(&file_handle TSRMLS_CC); fastcgi_request_done: + if (primary_script) { + efree(primary_script); + } + if (request_body_fd != -1) { close(request_body_fd); } diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index 33b9e410e..840eec73e 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -19,6 +19,9 @@ #include "fpm_php.h" #include "fpm_cleanup.h" #include "fpm_worker_pool.h" +#include "zlog.h" + +static char **limit_extensions = NULL; static int fpm_php_zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int mode, int stage TSRMLS_DC) /* {{{ */ { @@ -117,13 +120,13 @@ static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp) /* {{{ */ for (kv = wp->config->php_values; kv; kv = kv->next) { if (fpm_php_apply_defines_ex(kv, ZEND_INI_USER) == -1) { - fprintf(stderr, "Unable to set php_value '%s'", kv->key); + zlog(ZLOG_ERROR, "Unable to set php_value '%s'", kv->key); } } for (kv = wp->config->php_admin_values; kv; kv = kv->next) { if (fpm_php_apply_defines_ex(kv, ZEND_INI_SYSTEM) == -1) { - fprintf(stderr, "Unable to set php_admin_value '%s'", kv->key); + zlog(ZLOG_ERROR, "Unable to set php_admin_value '%s'", kv->key); } } @@ -219,7 +222,38 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ 0 > fpm_php_set_allowed_clients(wp)) { return -1; } + + if (wp->limit_extensions) { + limit_extensions = wp->limit_extensions; + } return 0; } /* }}} */ +int fpm_php_limit_extensions(char *path) /* {{{ */ +{ + char **p; + size_t path_len; + + if (!path || !limit_extensions) { + return 0; /* allowed by default */ + } + + p = limit_extensions; + path_len = strlen(path); + while (p && *p) { + size_t ext_len = strlen(*p); + if (path_len > ext_len) { + char *path_ext = path + path_len - ext_len; + if (strcmp(*p, path_ext) == 0) { + return 0; /* allow as the extension has been found */ + } + } + p++; + } + + + zlog(ZLOG_NOTICE, "Access to the script '%s' has been denied (see security.limit_extensions)", path); + return 1; /* extension not found: not allowed */ +} +/* }}} */ diff --git a/sapi/fpm/fpm/fpm_php.h b/sapi/fpm/fpm/fpm_php.h index 62a47e7fd..a2c7ed318 100644 --- a/sapi/fpm/fpm/fpm_php.h +++ b/sapi/fpm/fpm/fpm_php.h @@ -43,6 +43,7 @@ size_t fpm_php_content_length(TSRMLS_D); void fpm_php_soft_quit(); int fpm_php_init_main(); int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode); +int fpm_php_limit_extensions(char *path); #endif diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c index 03874584f..cd97aebb3 100644 --- a/sapi/fpm/fpm/fpm_php_trace.c +++ b/sapi/fpm/fpm/fpm_php_trace.c @@ -144,7 +144,7 @@ void fpm_php_trace(struct fpm_child_s *child) /* {{{ */ slowlog = fopen(child->wp->config->slowlog, "a+"); if (!slowlog) { - zlog(ZLOG_SYSERROR, "fopen(%s) failed", child->wp->config->slowlog); + zlog(ZLOG_SYSERROR, "unable to open slowlog (%s)", child->wp->config->slowlog); goto done0; } diff --git a/sapi/fpm/fpm/fpm_process_ctl.c b/sapi/fpm/fpm/fpm_process_ctl.c index 0f2685c73..e698eb0ca 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.c +++ b/sapi/fpm/fpm/fpm_process_ctl.c @@ -99,7 +99,7 @@ static void fpm_pctl_exec() /* {{{ */ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC); execvp(saved_argv[0], saved_argv); - zlog(ZLOG_SYSERROR, "execvp() failed"); + zlog(ZLOG_SYSERROR, "failed to reload: execvp() failed"); exit(1); } /* }}} */ @@ -317,7 +317,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ int idle = 0; int active = 0; int children_to_fork; - unsigned cur_lq; + unsigned cur_lq = 0; if (wp->config == NULL) continue; @@ -352,9 +352,26 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ } #endif } - fpm_scoreboard_update(idle, active, cur_lq, -1, -1, -1, FPM_SCOREBOARD_ACTION_SET, wp->scoreboard); } + fpm_scoreboard_update(idle, active, cur_lq, -1, -1, -1, FPM_SCOREBOARD_ACTION_SET, wp->scoreboard); + /* this is specific to PM_STYLE_ONDEMAND */ + if (wp->config->pm == PM_STYLE_ONDEMAND) { + struct timeval last, now; + + zlog(ZLOG_DEBUG, "[pool %s] currently %d active children, %d spare children", wp->config->name, active, idle); + + if (!last_idle_child) continue; + + fpm_request_last_activity(last_idle_child, &last); + fpm_clock_get(&now); + if (last.tv_sec < now.tv_sec - wp->config->pm_process_idle_timeout) { + last_idle_child->idle_kill = 1; + fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT); + } + + continue; + } /* the rest is only used by PM_STYLE_DYNAMIC */ if (wp->config->pm != PM_STYLE_DYNAMIC) continue; @@ -436,9 +453,13 @@ void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ * return; } + /* ensure heartbeat is not lower than FPM_PCTL_MIN_HEARTBEAT */ + fpm_globals.heartbeat = MAX(fpm_globals.heartbeat, FPM_PCTL_MIN_HEARTBEAT); + /* first call without setting to initialize the timer */ + zlog(ZLOG_DEBUG, "heartbeat have been set up with a timeout of %dms", fpm_globals.heartbeat); fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_heartbeat, NULL); - fpm_event_add(&heartbeat, FPM_PCTL_HEARTBEAT); + fpm_event_add(&heartbeat, fpm_globals.heartbeat); } /* }}} */ @@ -472,3 +493,47 @@ void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, } /* }}} */ +void fpm_pctl_on_socket_accept(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ +{ + struct fpm_worker_pool_s *wp = (struct fpm_worker_pool_s *)arg; + struct fpm_child_s *child; + + + if (fpm_globals.parent_pid != getpid()) { + /* prevent a event race condition when child process + * have not set up its own event loop */ + return; + } + + wp->socket_event_set = 0; + +/* zlog(ZLOG_DEBUG, "[pool %s] heartbeat running_children=%d", wp->config->name, wp->running_children);*/ + + if (wp->running_children >= wp->config->pm_max_children) { + if (!wp->warn_max_children) { + fpm_scoreboard_update(0, 0, 0, 0, 0, 1, FPM_SCOREBOARD_ACTION_INC, wp->scoreboard); + zlog(ZLOG_WARNING, "[pool %s] server reached max_children setting (%d), consider raising it", wp->config->name, wp->config->pm_max_children); + wp->warn_max_children = 1; + } + + return; + } + + for (child = wp->children; child; child = child->next) { + /* if there is at least on idle child, it will handle the connection, stop here */ + if (fpm_request_is_idle(child)) { + return; + } + } + + wp->warn_max_children = 0; + fpm_children_make(wp, 1, 1, 1); + + if (fpm_globals.is_child) { + return; + } + + zlog(ZLOG_DEBUG, "[pool %s] got accept without idle child available .... I forked", wp->config->name); +} +/* }}} */ + diff --git a/sapi/fpm/fpm/fpm_process_ctl.h b/sapi/fpm/fpm/fpm_process_ctl.h index 6bfcfd8c6..86a6ef0df 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.h +++ b/sapi/fpm/fpm/fpm_process_ctl.h @@ -11,8 +11,9 @@ #define FPM_MAX_SPAWN_RATE (32) /* 1s (in ms) heartbeat for idle server maintenance */ #define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000) -/* 130ms heartbeat for pctl */ -#define FPM_PCTL_HEARTBEAT (130) +/* a minimum of 130ms heartbeat for pctl */ +#define FPM_PCTL_MIN_HEARTBEAT (130) + struct fpm_child_s; @@ -22,6 +23,7 @@ int fpm_pctl_kill(pid_t pid, int how); void fpm_pctl_kill_all(int signo); void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg); void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg); +void fpm_pctl_on_socket_accept(struct fpm_event_s *ev, short which, void *arg); int fpm_pctl_child_exited(); int fpm_pctl_init_main(); diff --git a/sapi/fpm/fpm/fpm_request.c b/sapi/fpm/fpm/fpm_request.c index e0d1815db..28332d0a9 100644 --- a/sapi/fpm/fpm/fpm_request.c +++ b/sapi/fpm/fpm/fpm_request.c @@ -23,6 +23,19 @@ #include "zlog.h" +static const char *requests_stages[] = { + [FPM_REQUEST_ACCEPTING] = "Idle", + [FPM_REQUEST_READING_HEADERS] = "Reading headers", + [FPM_REQUEST_INFO] = "Getting request informations", + [FPM_REQUEST_EXECUTING] = "Running", + [FPM_REQUEST_END] = "Ending", + [FPM_REQUEST_FINISHED] = "Finishing", +}; + +const char *fpm_request_get_stage_name(int stage) { + return requests_stages[stage]; +} + void fpm_request_accepting() /* {{{ */ { struct fpm_scoreboard_proc_s *proc; @@ -32,16 +45,12 @@ void fpm_request_accepting() /* {{{ */ proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { - zlog(ZLOG_WARNING, "unable to acquire proc scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_ACCEPTING; proc->tv = now; - proc->request_uri[0] = '\0'; - proc->request_method[0] = '\0'; - proc->script_filename[0] = '\0'; - proc->content_length = 0; fpm_scoreboard_proc_release(proc); /* idle++, active-- */ @@ -67,7 +76,7 @@ void fpm_request_reading_headers() /* {{{ */ proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { - zlog(ZLOG_WARNING, "unable to acquire proc scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } @@ -78,6 +87,14 @@ void fpm_request_reading_headers() /* {{{ */ #ifdef HAVE_TIMES proc->cpu_accepted = cpu; #endif + proc->requests++; + proc->request_uri[0] = '\0'; + proc->request_method[0] = '\0'; + proc->script_filename[0] = '\0'; + proc->query_string[0] = '\0'; + proc->query_string[0] = '\0'; + proc->auth_user[0] = '\0'; + proc->content_length = 0; fpm_scoreboard_proc_release(proc); /* idle--, active++, request++ */ @@ -101,7 +118,7 @@ void fpm_request_info() /* {{{ */ proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { - zlog(ZLOG_WARNING, "unable to acquire proc scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } @@ -145,7 +162,7 @@ void fpm_request_executing() /* {{{ */ proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { - zlog(ZLOG_WARNING, "unable to acquire proc scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } @@ -171,14 +188,18 @@ void fpm_request_end(TSRMLS_D) /* {{{ */ proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { - zlog(ZLOG_WARNING, "unable to acquire proc scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_FINISHED; proc->tv = now; + timersub(&now, &proc->accepted, &proc->duration); #ifdef HAVE_TIMES - proc->cpu_finished = cpu; timersub(&proc->tv, &proc->accepted, &proc->cpu_duration); + proc->last_request_cpu.tms_utime = cpu.tms_utime - proc->cpu_accepted.tms_utime; + proc->last_request_cpu.tms_stime = cpu.tms_stime - proc->cpu_accepted.tms_stime; + proc->last_request_cpu.tms_cutime = cpu.tms_cutime - proc->cpu_accepted.tms_cutime; + proc->last_request_cpu.tms_cstime = cpu.tms_cstime - proc->cpu_accepted.tms_cstime; #endif proc->memory = memory; fpm_scoreboard_proc_release(proc); @@ -194,7 +215,7 @@ void fpm_request_finished() /* {{{ */ proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { - zlog(ZLOG_WARNING, "unable to acquire proc scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } @@ -212,7 +233,7 @@ void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, proc_p = fpm_scoreboard_proc_acquire(child->wp->scoreboard, child->scoreboard_i, 1); if (!proc_p) { - zlog(ZLOG_WARNING, "unable to acquire scoreboard"); + zlog(ZLOG_WARNING, "failed to acquire scoreboard"); return; } @@ -276,3 +297,20 @@ int fpm_request_is_idle(struct fpm_child_s *child) /* {{{ */ return proc->request_stage == FPM_REQUEST_ACCEPTING; } /* }}} */ + +int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv) /* {{{ */ +{ + struct fpm_scoreboard_proc_s *proc; + + if (!tv) return -1; + + proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i); + if (!proc) { + return -1; + } + + *tv = proc->tv; + + return 1; +} +/* }}} */ diff --git a/sapi/fpm/fpm/fpm_request.h b/sapi/fpm/fpm/fpm_request.h index b3014a5f1..aebd36cff 100644 --- a/sapi/fpm/fpm/fpm_request.h +++ b/sapi/fpm/fpm/fpm_request.h @@ -17,6 +17,8 @@ struct timeval; void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *tv, int terminate_timeout, int slowlog_timeout); int fpm_request_is_idle(struct fpm_child_s *child); +const char *fpm_request_get_stage_name(int stage); +int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv); enum fpm_request_stage_e { FPM_REQUEST_ACCEPTING = 1, diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c index 5ff5e5f9f..4222f6037 100644 --- a/sapi/fpm/fpm/fpm_scoreboard.c +++ b/sapi/fpm/fpm/fpm_scoreboard.c @@ -17,12 +17,30 @@ static struct fpm_scoreboard_s *fpm_scoreboard = NULL; static int fpm_scoreboard_i = -1; +#ifdef HAVE_TIMES +static float fpm_scoreboard_tick; +#endif + int fpm_scoreboard_init_main() /* {{{ */ { struct fpm_worker_pool_s *wp; int i; +#ifdef HAVE_TIMES +#if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)) + fpm_scoreboard_tick = sysconf(_SC_CLK_TCK); +#else /* _SC_CLK_TCK */ +#ifdef HZ + fpm_scoreboard_tick = HZ; +#else /* HZ */ + fpm_scoreboard_tick = 100; +#endif /* HZ */ +#endif /* _SC_CLK_TCK */ + zlog(ZLOG_DEBUG, "got clock tick '%.0f'", fpm_scoreboard_tick); +#endif /* HAVE_TIMES */ + + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { if (wp->config->pm_max_children < 1) { zlog(ZLOG_ERROR, "[pool %s] Unable to create scoreboard SHM because max_client is not set", wp->config->name); @@ -233,6 +251,7 @@ void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_ind return; } proc->pid = pid; + proc->start_epoch = time(NULL); } /* }}} */ @@ -299,3 +318,11 @@ int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_in } /* }}} */ +#ifdef HAVE_TIMES +float fpm_scoreboard_get_tick() /* {{{ */ +{ + return fpm_scoreboard_tick; +} +/* }}} */ +#endif + diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h index e62c42d98..136ea481a 100644 --- a/sapi/fpm/fpm/fpm_scoreboard.h +++ b/sapi/fpm/fpm/fpm_scoreboard.h @@ -23,9 +23,12 @@ struct fpm_scoreboard_proc_s { char dummy[16]; }; int used; + time_t start_epoch; pid_t pid; + unsigned long requests; enum fpm_request_stage_e request_stage; struct timeval accepted; + struct timeval duration; time_t accepted_epoch; struct timeval tv; char request_uri[128]; @@ -36,8 +39,9 @@ struct fpm_scoreboard_proc_s { char auth_user[32]; #ifdef HAVE_TIMES struct tms cpu_accepted; - struct tms cpu_finished; struct timeval cpu_duration; + struct tms last_request_cpu; + struct timeval last_request_cpu_duration; #endif size_t memory; }; @@ -82,4 +86,8 @@ void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_ind void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index); int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index); +#ifdef HAVE_TIMES +float fpm_scoreboard_get_tick(); +#endif + #endif diff --git a/sapi/fpm/fpm/fpm_shm.c b/sapi/fpm/fpm/fpm_shm.c index a777612de..6acbddf9a 100644 --- a/sapi/fpm/fpm/fpm_shm.c +++ b/sapi/fpm/fpm/fpm_shm.c @@ -49,7 +49,7 @@ int fpm_shm_free(void *mem, size_t size) /* {{{ */ } if (munmap(mem, size) == -1) { - zlog(ZLOG_SYSERROR, "Unable to free shm: %s", strerror(errno)); + zlog(ZLOG_SYSERROR, "Unable to free shm"); return 0; } diff --git a/sapi/fpm/fpm/fpm_signals.c b/sapi/fpm/fpm/fpm_signals.c index 7c317e576..8993a860a 100644 --- a/sapi/fpm/fpm/fpm_signals.c +++ b/sapi/fpm/fpm/fpm_signals.c @@ -182,17 +182,17 @@ int fpm_signals_init_main() /* {{{ */ struct sigaction act; if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) { - zlog(ZLOG_SYSERROR, "socketpair() failed"); + zlog(ZLOG_SYSERROR, "failed to init signals: socketpair()"); return -1; } if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) { - zlog(ZLOG_SYSERROR, "fd_set_blocked() failed"); + zlog(ZLOG_SYSERROR, "failed to init signals: fd_set_blocked()"); return -1; } if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) { - zlog(ZLOG_SYSERROR, "fcntl(F_SETFD, FD_CLOEXEC) failed"); + zlog(ZLOG_SYSERROR, "falied to init signals: fcntl(F_SETFD, FD_CLOEXEC)"); return -1; } @@ -207,7 +207,7 @@ int fpm_signals_init_main() /* {{{ */ 0 > sigaction(SIGCHLD, &act, 0) || 0 > sigaction(SIGQUIT, &act, 0)) { - zlog(ZLOG_SYSERROR, "sigaction() failed"); + zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()"); return -1; } return 0; @@ -236,7 +236,7 @@ int fpm_signals_init_child() /* {{{ */ 0 > sigaction(SIGCHLD, &act_dfl, 0) || 0 > sigaction(SIGQUIT, &act, 0)) { - zlog(ZLOG_SYSERROR, "sigaction() failed"); + zlog(ZLOG_SYSERROR, "failed to init child signals: sigaction()"); return -1; } return 0; diff --git a/sapi/fpm/fpm/fpm_sockets.c b/sapi/fpm/fpm/fpm_sockets.c index 08e2342e5..cb4897e9b 100644 --- a/sapi/fpm/fpm/fpm_sockets.c +++ b/sapi/fpm/fpm/fpm_sockets.c @@ -172,7 +172,7 @@ static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct sock = socket(sa->sa_family, SOCK_STREAM, 0); if (0 > sock) { - zlog(ZLOG_SYSERROR, "socket() failed"); + zlog(ZLOG_SYSERROR, "failed to create new listening socket: socket()"); return -1; } @@ -184,7 +184,7 @@ static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct } if (0 > bind(sock, sa, socklen)) { - zlog(ZLOG_SYSERROR, "bind() for address '%s' failed", wp->config->listen_address); + zlog(ZLOG_SYSERROR, "unable to bind listening socket for address '%s'", wp->config->listen_address); if (wp->listen_address_domain == FPM_AF_UNIX) { umask(saved_umask); } @@ -198,14 +198,14 @@ static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct if (wp->socket_uid != -1 || wp->socket_gid != -1) { if (0 > chown(path, wp->socket_uid, wp->socket_gid)) { - zlog(ZLOG_SYSERROR, "chown() for address '%s' failed", wp->config->listen_address); + zlog(ZLOG_SYSERROR, "failed to chown() the socket '%s'", wp->config->listen_address); return -1; } } } if (0 > listen(sock, wp->config->listen_backlog)) { - zlog(ZLOG_SYSERROR, "listen() for address '%s' failed", wp->config->listen_address); + zlog(ZLOG_SYSERROR, "failed to listen to address '%s'", wp->config->listen_address); return -1; } @@ -392,7 +392,7 @@ int fpm_socket_get_listening_queue(int sock, unsigned *cur_lq, unsigned *max_lq) socklen_t len = sizeof(info); if (0 > getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &len)) { - zlog(ZLOG_SYSERROR, "unable to retrieve TCP_INFO for socket"); + zlog(ZLOG_SYSERROR, "failed to retrieve TCP_INFO for socket"); return -1; } diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index 8d7b75997..a20e2dd89 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -1,5 +1,5 @@ - /* $Id: fpm_status.c 312914 2011-07-04 21:29:32Z fat $ */ + /* $Id: fpm_status.c 317901 2011-10-08 14:04:09Z fat $ */ /* (c) 2009 Jerome Loyet */ #include "php.h" @@ -13,6 +13,8 @@ #include "fpm_scoreboard.h" #include "zlog.h" #include "fpm_atomic.h" +#include "fpm_conf.h" +#include <ext/standard/html.h> static char *fpm_status_uri = NULL; static char *fpm_status_ping_uri = NULL; @@ -32,7 +34,7 @@ int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ if (wp->config->ping_path) { if (!wp->config->ping_response) { - zlog(ZLOG_ERROR, "[pool %s] ping is set (%s) but pong is not set.", wp->config->name, wp->config->ping_path); + zlog(ZLOG_ERROR, "[pool %s] ping is set (%s) but ping.response is not set.", wp->config->name, wp->config->ping_path); return -1; } fpm_status_ping_uri = strdup(wp->config->ping_path); @@ -46,9 +48,12 @@ int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ { struct fpm_scoreboard_s scoreboard, *scoreboard_p; -// struct fpm_scoreboard_proc_s proc; - char *buffer, *syntax, *time_format, time_buffer[64]; + struct fpm_scoreboard_proc_s proc; + char *buffer, *time_format, time_buffer[64]; time_t now_epoch; + int full, encode; + char *short_syntax, *short_post; + char *full_pre, *full_syntax, *full_post, *full_separator; if (!SG(request_info).request_uri) { return 0; @@ -56,6 +61,7 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ /* PING */ if (fpm_status_ping_uri && fpm_status_ping_response && !strcmp(fpm_status_ping_uri, SG(request_info).request_uri)) { + fpm_request_executing(); sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC); @@ -72,6 +78,7 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ /* STATUS */ if (fpm_status_uri && !strcmp(fpm_status_uri, SG(request_info).request_uri)) { + fpm_request_executing(); scoreboard_p = fpm_scoreboard_get(); if (!scoreboard_p) { @@ -117,12 +124,23 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ return 1; } + /* full status ? */ + full = SG(request_info).request_uri && strstr(SG(request_info).query_string, "full"); + short_syntax = short_post = NULL; + full_separator = full_pre = full_syntax = full_post = NULL; + encode = 0; + /* HTML */ if (SG(request_info).query_string && strstr(SG(request_info).query_string, "html")) { sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1 TSRMLS_CC); time_format = "%d/%b/%Y:%H:%M:%S %z"; + encode = 1; - syntax = + short_syntax = + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" + "<head><title>PHP-FPM Status Page</title></head>\n" + "<body>\n" "<table>\n" "<tr><th>pool</th><td>%s</td></tr>\n" "<tr><th>process manager</th><td>%s</td></tr>\n" @@ -141,12 +159,58 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ "<tr><th>max children reached</th><td>%u</td></tr>\n" "</table>\n"; + if (!full) { + short_post = "</body></html>"; + } else { + full_pre = + "<table border=\"1\">\n" + "<tr>" + "<th>pid</th>" + "<th>state</th>" + "<th>start time</th>" + "<th>start since</th>" + "<th>requests</th>" + "<th>request duration</th>" + "<th>request method</th>" + "<th>request uri</th>" + "<th>content length</th>" + "<th>user</th>" + "<th>script</th>" +#if HAVE_FPM_LQ + "<th>last request cpu</th>" +#endif + "<th>last request memory</th>" + "</tr>\n"; + + full_syntax = + "<tr>" + "<td>%d</td>" + "<td>%s</td>" + "<td>%s</td>" + "<td>%lu</td>" + "<td>%lu</td>" + "<td>%lu</td>" + "<td>%s</td>" + "<td>%s%s%s</td>" + "<td>%zu</td>" + "<td>%s</td>" + "<td>%s</td>" +#if HAVE_FPM_LQ + "<td>%.2f</td>" +#endif + "<td>%zu</td>" + "</tr>\n"; + + full_post = "</table></body></html>"; + } + /* XML */ } else if (SG(request_info).request_uri && strstr(SG(request_info).query_string, "xml")) { sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1 TSRMLS_CC); time_format = "%s"; + encode = 1; - syntax = + short_syntax = "<?xml version=\"1.0\" ?>\n" "<status>\n" "<pool>%s</pool>\n" @@ -163,14 +227,40 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ "<active-processes>%d</active-processes>\n" "<total-processes>%d</total-processes>\n" "<max-active-processes>%d</max-active-processes>\n" - "<max-children-reached>%u</max-children-reached>\n" - "</status>"; + "<max-children-reached>%u</max-children-reached>\n"; + + if (!full) { + short_post = "</status>"; + } else { + full_pre = "<processes>\n"; + full_syntax = + "<process>" + "<pid>%d</pid>" + "<state>%s</state>" + "<start-time>%s</start-time>" + "<start-since>%lu</start-since>" + "<requests>%lu</requests>" + "<request-duration>%lu</request-duration>" + "<request-method>%s</request-method>" + "<request-uri>%s%s%s</request-uri>" + "<content-length>%zu</content-length>" + "<user>%s</user>" + "<script>%s</script>" +#if HAVE_FPM_LQ + "<last-request-cpu>%.2f</last-request-cpu>" +#endif + "<last-request-memory>%zu</last-request-memory>" + "</process>\n" + ; + full_post = "</processes>\n</status>"; + } /* JSON */ } else if (SG(request_info).request_uri && strstr(SG(request_info).query_string, "json")) { sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1 TSRMLS_CC); time_format = "%s"; - syntax = + + short_syntax = "{" "\"pool\":\"%s\"," "\"process manager\":\"%s\"," @@ -186,14 +276,41 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ "\"active processes\":%d," "\"total processes\":%d," "\"max active processes\":%d," - "\"max children reached\":%u" - "}"; + "\"max children reached\":%u"; + + if (!full) { + short_post = "}"; + } else { + full_separator = ","; + full_pre = ", \"processes\":["; + + full_syntax = "{" + "\"pid\":%d," + "\"state\":\"%s\"," + "\"start time\":%s," + "\"start since\":%lu," + "\"requests\":%lu," + "\"request duration\":%lu," + "\"request method\":\"%s\"," + "\"request uri\":\"%s%s%s\"," + "\"content length\":%zu," + "\"user\":\"%s\"," + "\"script\":\"%s\"," +#if HAVE_FPM_LQ + "\"last request cpu\":%.2f," +#endif + "\"last request memory\":%zu" + "}"; + + full_post = "]}"; + } /* TEXT */ } else { sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); time_format = "%d/%b/%Y:%H:%M:%S %z"; - syntax = + + short_syntax = "pool: %s\n" "process manager: %s\n" "start time: %s\n" @@ -209,13 +326,34 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ "total processes: %d\n" "max active processes: %d\n" "max children reached: %u\n"; + + if (full) { + full_syntax = + "\n" + "************************\n" + "pid: %d\n" + "state: %s\n" + "start time: %s\n" + "start since: %lu\n" + "requests: %lu\n" + "request duration: %lu\n" + "request method: %s\n" + "request URI: %s%s%s\n" + "content length: %zu\n" + "user: %s\n" + "script: %s\n" +#ifdef HAVE_FPM_LQ + "last request cpu: %.2f\n" +#endif + "last request memory: %zu\n"; + } } strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&scoreboard.start_epoch)); now_epoch = time(NULL); - spprintf(&buffer, 0, syntax, + spprintf(&buffer, 0, short_syntax, scoreboard.pool, - scoreboard.pm == PM_STYLE_STATIC ? "static" : "dynamic", + PM2STR(scoreboard.pm), time_buffer, now_epoch - scoreboard.start_epoch, scoreboard.requests, @@ -233,6 +371,96 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ PUTS(buffer); efree(buffer); + if (short_post) { + PUTS(short_post); + } + + /* no need to test the var 'full' */ + if (full_syntax) { + int i, len, first; + char *query_string; + struct timeval duration, now; +#ifdef HAVE_FPM_LQ + float cpu; +#endif + + fpm_clock_get(&now); + + if (full_pre) { + PUTS(full_pre); + } + + first = 1; + for (i=0; i<scoreboard_p->nprocs; i++) { + if (!scoreboard_p->procs[i] || !scoreboard_p->procs[i]->used) { + continue; + } + proc = *scoreboard_p->procs[i]; + + if (first) { + first = 0; + } else { + if (full_separator) { + PUTS(full_separator); + } + } + + query_string = NULL; + len = 0; + if (proc.query_string[0] != '\0') { + if (!encode) { + query_string = proc.query_string; + } else { + query_string = php_escape_html_entities_ex((unsigned char *)proc.query_string, strlen(proc.query_string), &len, 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, 1 TSRMLS_CC); + } + } + +#ifdef HAVE_FPM_LQ + /* prevent NaN */ + if (proc.cpu_duration.tv_sec == 0 && proc.cpu_duration.tv_usec == 0) { + cpu = 0.; + } else { + cpu = (proc.last_request_cpu.tms_utime + proc.last_request_cpu.tms_stime + proc.last_request_cpu.tms_cutime + proc.last_request_cpu.tms_cstime) / fpm_scoreboard_get_tick() / (proc.cpu_duration.tv_sec + proc.cpu_duration.tv_usec / 1000000.) * 100.; + } +#endif + + if (proc.request_stage == FPM_REQUEST_ACCEPTING) { + duration = proc.duration; + } else { + timersub(&now, &proc.accepted, &duration); + } + strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&proc.start_epoch)); + spprintf(&buffer, 0, full_syntax, + proc.pid, + fpm_request_get_stage_name(proc.request_stage), + time_buffer, + now_epoch - proc.start_epoch, + proc.requests, + duration.tv_sec * 1000000UL + duration.tv_usec, + proc.request_method[0] != '\0' ? proc.request_method : "-", + proc.request_uri[0] != '\0' ? proc.request_uri : "-", + query_string ? "?" : "", + query_string ? query_string : "", + proc.content_length, + proc.auth_user[0] != '\0' ? proc.auth_user : "-", + proc.script_filename[0] != '\0' ? proc.script_filename : "-", +#ifdef HAVE_FPM_LQ + proc.request_stage == FPM_REQUEST_ACCEPTING ? cpu : 0., +#endif + proc.request_stage == FPM_REQUEST_ACCEPTING ? proc.memory : 0); + PUTS(buffer); + efree(buffer); + + if (len > 0 && query_string) { + efree(query_string); + } + } + + if (full_post) { + PUTS(full_post); + } + } + return 1; } diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index 571f3074b..6a587d00e 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -11,6 +11,8 @@ #include <unistd.h> #include <errno.h> +#include "php_syslog.h" + #include "fpm.h" #include "fpm_children.h" #include "fpm_events.h" @@ -26,12 +28,12 @@ int fpm_stdio_init_main() /* {{{ */ int fd = open("/dev/null", O_RDWR); if (0 > fd) { - zlog(ZLOG_SYSERROR, "open(\"/dev/null\") failed"); + zlog(ZLOG_SYSERROR, "failed to init stdio: open(\"/dev/null\")"); return -1; } if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) { - zlog(ZLOG_SYSERROR, "dup2() failed"); + zlog(ZLOG_SYSERROR, "failed to init stdio: dup2()"); return -1; } close(fd); @@ -42,10 +44,12 @@ int fpm_stdio_init_main() /* {{{ */ int fpm_stdio_init_final() /* {{{ */ { if (fpm_global_config.daemonize) { - if (fpm_globals.error_log_fd != STDERR_FILENO) { - /* there might be messages to stderr from libevent, we need to log them all */ + /* prevent duping if logging to syslog */ + if (fpm_globals.error_log_fd > 0 && fpm_globals.error_log_fd != STDERR_FILENO) { + + /* there might be messages to stderr from other parts of the code, we need to log them all */ if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) { - zlog(ZLOG_SYSERROR, "dup2() failed"); + zlog(ZLOG_SYSERROR, "failed to init stdio: dup2()"); return -1; } } @@ -57,13 +61,20 @@ int fpm_stdio_init_final() /* {{{ */ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ { - close(fpm_globals.error_log_fd); +#ifdef HAVE_SYSLOG_H + if (fpm_globals.error_log_fd == ZLOG_SYSLOG) { + closelog(); /* ensure to close syslog not to interrupt with PHP syslog code */ + } else +#endif + if (fpm_globals.error_log_fd > 0) { + close(fpm_globals.error_log_fd); + } fpm_globals.error_log_fd = -1; zlog_set_fd(-1); if (wp->listening_socket != STDIN_FILENO) { if (0 > dup2(wp->listening_socket, STDIN_FILENO)) { - zlog(ZLOG_SYSERROR, "dup2() failed"); + zlog(ZLOG_SYSERROR, "failed to init child stdio: dup2()"); return -1; } } @@ -105,7 +116,7 @@ static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) } else { /* error or pipe is closed */ if (res < 0) { /* error */ - zlog(ZLOG_SYSERROR, "read() failed"); + zlog(ZLOG_SYSERROR, "unable to read what child say"); } fpm_event_del(event); @@ -175,20 +186,23 @@ int fpm_stdio_prepare_pipes(struct fpm_child_s *child) /* {{{ */ } if (0 > pipe(fd_stdout)) { - zlog(ZLOG_SYSERROR, "pipe() failed"); + zlog(ZLOG_SYSERROR, "failed to prepare the stdout pipe"); return -1; } if (0 > pipe(fd_stderr)) { - zlog(ZLOG_SYSERROR, "pipe() failed"); - close(fd_stdout[0]); close(fd_stdout[1]); + zlog(ZLOG_SYSERROR, "failed to prepare the stderr pipe"); + close(fd_stdout[0]); + close(fd_stdout[1]); return -1; } if (0 > fd_set_blocked(fd_stdout[0], 0) || 0 > fd_set_blocked(fd_stderr[0], 0)) { - zlog(ZLOG_SYSERROR, "fd_set_blocked() failed"); - close(fd_stdout[0]); close(fd_stdout[1]); - close(fd_stderr[0]); close(fd_stderr[1]); + zlog(ZLOG_SYSERROR, "failed to unblock pipes"); + close(fd_stdout[0]); + close(fd_stdout[1]); + close(fd_stderr[0]); + close(fd_stderr[1]); return -1; } return 0; @@ -249,9 +263,20 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ { int fd; +#ifdef HAVE_SYSLOG_H + if (!strcasecmp(fpm_global_config.error_log, "syslog")) { + openlog(fpm_global_config.syslog_ident, LOG_PID | LOG_CONS, fpm_global_config.syslog_facility); + fpm_globals.error_log_fd = ZLOG_SYSLOG; + if (fpm_global_config.daemonize) { + zlog_set_fd(fpm_globals.error_log_fd); + } + return 0; + } +#endif + fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (0 > fd) { - zlog(ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log); + zlog(ZLOG_SYSERROR, "failed to open error_log (%s)", fpm_global_config.error_log); return -1; } diff --git a/sapi/fpm/fpm/fpm_trace_mach.c b/sapi/fpm/fpm/fpm_trace_mach.c index fe26fd9e2..3b85e6a34 100644 --- a/sapi/fpm/fpm/fpm_trace_mach.c +++ b/sapi/fpm/fpm/fpm_trace_mach.c @@ -37,7 +37,7 @@ static int fpm_mach_vm_read_page(vm_offset_t page) /* {{{ */ kr = mach_vm_read(target, page, fpm_pagesize, &local_page, &local_size); if (kr != KERN_SUCCESS) { - zlog(ZLOG_ERROR, "mach_vm_read() failed: %s (%d)", mach_error_string(kr), kr); + zlog(ZLOG_ERROR, "failed to read vm page: mach_vm_read(): %s (%d)", mach_error_string(kr), kr); return -1; } return 0; @@ -47,7 +47,7 @@ static int fpm_mach_vm_read_page(vm_offset_t page) /* {{{ */ int fpm_trace_signal(pid_t pid) /* {{{ */ { if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) { - zlog(ZLOG_SYSERROR, "kill(SIGSTOP) failed"); + zlog(ZLOG_SYSERROR, "failed to send SIGSTOP to %d", pid); return -1; } return 0; diff --git a/sapi/fpm/fpm/fpm_trace_pread.c b/sapi/fpm/fpm/fpm_trace_pread.c index eda84928e..6a6155740 100644 --- a/sapi/fpm/fpm/fpm_trace_pread.c +++ b/sapi/fpm/fpm/fpm_trace_pread.c @@ -26,7 +26,7 @@ static int mem_file = -1; int fpm_trace_signal(pid_t pid) /* {{{ */ { if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) { - zlog(ZLOG_SYSERROR, "kill(SIGSTOP) failed"); + zlog(ZLOG_SYSERROR, "failed to send SIGSTOP to %d", pid); return -1; } return 0; @@ -40,7 +40,7 @@ int fpm_trace_ready(pid_t pid) /* {{{ */ sprintf(buf, "/proc/%d/" PROC_MEM_FILE, (int) pid); mem_file = open(buf, O_RDONLY); if (0 > mem_file) { - zlog(ZLOG_SYSERROR, "open(%s) failed", buf); + zlog(ZLOG_SYSERROR, "failed to open %s", buf); return -1; } return 0; diff --git a/sapi/fpm/fpm/fpm_trace_ptrace.c b/sapi/fpm/fpm/fpm_trace_ptrace.c index 395c1ac08..838c61867 100644 --- a/sapi/fpm/fpm/fpm_trace_ptrace.c +++ b/sapi/fpm/fpm/fpm_trace_ptrace.c @@ -29,7 +29,7 @@ static pid_t traced_pid; int fpm_trace_signal(pid_t pid) /* {{{ */ { if (0 > ptrace(PTRACE_ATTACH, pid, 0, 0)) { - zlog(ZLOG_SYSERROR, "ptrace(ATTACH) failed"); + zlog(ZLOG_SYSERROR, "failed to ptrace(ATTACH) child %d", pid); return -1; } return 0; @@ -46,7 +46,7 @@ int fpm_trace_ready(pid_t pid) /* {{{ */ int fpm_trace_close(pid_t pid) /* {{{ */ { if (0 > ptrace(PTRACE_DETACH, pid, (void *) 1, 0)) { - zlog(ZLOG_SYSERROR, "ptrace(DETACH) failed"); + zlog(ZLOG_SYSERROR, "failed to ptrace(DETACH) child %d", pid); return -1; } traced_pid = 0; @@ -65,14 +65,14 @@ int fpm_trace_get_long(long addr, long *data) /* {{{ */ }; if (0 > ptrace(PT_IO, traced_pid, (void *) &ptio, 0)) { - zlog(ZLOG_SYSERROR, "ptrace(PT_IO) failed"); + zlog(ZLOG_SYSERROR, "failed to ptrace(PT_IO) pid %d", traced_pid); return -1; } #else errno = 0; *data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0); if (errno) { - zlog(ZLOG_SYSERROR, "ptrace(PEEKDATA) failed"); + zlog(ZLOG_SYSERROR, "failed to ptrace(PEEKDATA) pid %d", traced_pid); return -1; } #endif diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index d29d38799..17d0b8125 100644 --- a/sapi/fpm/fpm/fpm_unix.c +++ b/sapi/fpm/fpm/fpm_unix.c @@ -73,6 +73,7 @@ int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ { + struct passwd *pwd; int is_root = !geteuid(); if (is_root) { @@ -119,23 +120,20 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ #endif } else { /* not root */ if (wp->config->user && *wp->config->user) { - zlog(ZLOG_WARNING, "[pool %s] 'user' directive is ignored", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'user' directive is ignored when FPM is not running as root", wp->config->name); } if (wp->config->group && *wp->config->group) { - zlog(ZLOG_WARNING, "[pool %s] 'group' directive is ignored", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'group' directive is ignored when FPM is not running as root", wp->config->name); } if (wp->config->chroot && *wp->config->chroot) { - zlog(ZLOG_WARNING, "[pool %s] 'chroot' directive is ignored", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'chroot' directive is ignored when FPM is not running as root", wp->config->name); } - { /* set up HOME and USER anyway */ - struct passwd *pwd; - - pwd = getpwuid(getuid()); - if (pwd) { - wp->user = strdup(pwd->pw_name); - wp->home = strdup(pwd->pw_dir); - } + /* set up HOME and USER anyway */ + pwd = getpwuid(getuid()); + if (pwd) { + wp->user = strdup(pwd->pw_name); + wp->home = strdup(pwd->pw_dir); } } return 0; @@ -153,7 +151,7 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ r.rlim_max = r.rlim_cur = (rlim_t) wp->config->rlimit_files; if (0 > setrlimit(RLIMIT_NOFILE, &r)) { - zlog(ZLOG_SYSERROR, "[pool %s] unable to set rlimit_files for this pool. Please check your system limits or decrease rlimit_files. setrlimit(RLIMIT_NOFILE, %d) failed (%d)", wp->config->name, wp->config->rlimit_files, errno); + zlog(ZLOG_SYSERROR, "[pool %s] failed to set rlimit_files for this pool. Please check your system limits or decrease rlimit_files. setrlimit(RLIMIT_NOFILE, %d)", wp->config->name, wp->config->rlimit_files); } } @@ -163,13 +161,13 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ r.rlim_max = r.rlim_cur = wp->config->rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_core; if (0 > setrlimit(RLIMIT_CORE, &r)) { - zlog(ZLOG_SYSERROR, "[pool %s] unable to set rlimit_core for this pool. Please check your system limits or decrease rlimit_core. setrlimit(RLIMIT_CORE, %d) failed (%d)", wp->config->name, wp->config->rlimit_core, errno); + zlog(ZLOG_SYSERROR, "[pool %s] failed to set rlimit_core for this pool. Please check your system limits or decrease rlimit_core. setrlimit(RLIMIT_CORE, %d)", wp->config->name, wp->config->rlimit_core); } } if (is_root && wp->config->chroot && *wp->config->chroot) { if (0 > chroot(wp->config->chroot)) { - zlog(ZLOG_SYSERROR, "[pool %s] chroot(%s) failed", wp->config->name, wp->config->chroot); + zlog(ZLOG_SYSERROR, "[pool %s] failed to chroot(%s)", wp->config->name, wp->config->chroot); return -1; } made_chroot = 1; @@ -177,7 +175,7 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ if (wp->config->chdir && *wp->config->chdir) { if (0 > chdir(wp->config->chdir)) { - zlog(ZLOG_SYSERROR, "[pool %s] chdir(%s) failed", wp->config->name, wp->config->chdir); + zlog(ZLOG_SYSERROR, "[pool %s] failed to chdir(%s)", wp->config->name, wp->config->chdir); return -1; } } else if (made_chroot) { @@ -187,17 +185,17 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ if (is_root) { if (wp->set_gid) { if (0 > setgid(wp->set_gid)) { - zlog(ZLOG_SYSERROR, "[pool %s] setgid(%d) failed", wp->config->name, wp->set_gid); + zlog(ZLOG_SYSERROR, "[pool %s] failed to setgid(%d)", wp->config->name, wp->set_gid); return -1; } } if (wp->set_uid) { if (0 > initgroups(wp->config->user, wp->set_gid)) { - zlog(ZLOG_SYSERROR, "[pool %s] initgroups(%s, %d) failed", wp->config->name, wp->config->user, wp->set_gid); + zlog(ZLOG_SYSERROR, "[pool %s] failed to initgroups(%s, %d)", wp->config->name, wp->config->user, wp->set_gid); return -1; } if (0 > setuid(wp->set_uid)) { - zlog(ZLOG_SYSERROR, "[pool %s] setuid(%d) failed", wp->config->name, wp->set_uid); + zlog(ZLOG_SYSERROR, "[pool %s] failed to setuid(%d)", wp->config->name, wp->set_uid); return -1; } } @@ -205,7 +203,7 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ #ifdef HAVE_PRCTL if (0 > prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) { - zlog(ZLOG_SYSERROR, "[pool %s] prctl(PR_SET_DUMPABLE) failed", wp->config->name); + zlog(ZLOG_SYSERROR, "[pool %s] failed to prctl(PR_SET_DUMPABLE)", wp->config->name); } #endif @@ -226,7 +224,7 @@ int fpm_unix_init_main() /* {{{ */ r.rlim_max = r.rlim_cur = (rlim_t) fpm_global_config.rlimit_files; if (0 > setrlimit(RLIMIT_NOFILE, &r)) { - zlog(ZLOG_SYSERROR, "unable to set rlimit_core for this pool. Please check your system limits or decrease rlimit_files. setrlimit(RLIMIT_NOFILE, %d) failed (%d)", fpm_global_config.rlimit_files, errno); + zlog(ZLOG_SYSERROR, "failed to set rlimit_core for this pool. Please check your system limits or decrease rlimit_files. setrlimit(RLIMIT_NOFILE, %d)", fpm_global_config.rlimit_files); return -1; } } @@ -237,7 +235,7 @@ int fpm_unix_init_main() /* {{{ */ r.rlim_max = r.rlim_cur = fpm_global_config.rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) fpm_global_config.rlimit_core; if (0 > setrlimit(RLIMIT_CORE, &r)) { - zlog(ZLOG_SYSERROR, "unable to set rlimit_core for this pool. Please check your system limits or decrease rlimit_core. setrlimit(RLIMIT_CORE, %d) failed (%d)", fpm_global_config.rlimit_core, errno); + zlog(ZLOG_SYSERROR, "failed to set rlimit_core for this pool. Please check your system limits or decrease rlimit_core. setrlimit(RLIMIT_CORE, %d)", fpm_global_config.rlimit_core); return -1; } } @@ -246,7 +244,7 @@ int fpm_unix_init_main() /* {{{ */ if (fpm_global_config.daemonize) { switch (fork()) { case -1 : - zlog(ZLOG_SYSERROR, "daemonized fork() failed"); + zlog(ZLOG_SYSERROR, "failed to daemonize"); return -1; case 0 : break; diff --git a/sapi/fpm/fpm/fpm_worker_pool.c b/sapi/fpm/fpm/fpm_worker_pool.c index 6c6d9cce0..123f9893f 100644 --- a/sapi/fpm/fpm/fpm_worker_pool.c +++ b/sapi/fpm/fpm/fpm_worker_pool.c @@ -15,7 +15,6 @@ #include "fpm_shm.h" #include "fpm_scoreboard.h" #include "fpm_conf.h" -#include "zlog.h" struct fpm_worker_pool_s *fpm_worker_all_pools; diff --git a/sapi/fpm/fpm/fpm_worker_pool.h b/sapi/fpm/fpm/fpm_worker_pool.h index 098def5b7..6688e6d3b 100644 --- a/sapi/fpm/fpm/fpm_worker_pool.h +++ b/sapi/fpm/fpm/fpm_worker_pool.h @@ -37,6 +37,11 @@ struct fpm_worker_pool_s { #endif struct fpm_scoreboard_s *scoreboard; int log_fd; + char **limit_extensions; + + /* for ondemand PM */ + struct fpm_event_s *ondemand_event; + int socket_event_set; }; struct fpm_worker_pool_s *fpm_worker_pool_alloc(); diff --git a/sapi/fpm/fpm/zlog.c b/sapi/fpm/fpm/zlog.c index 6b062eb8a..b127ec16f 100644 --- a/sapi/fpm/fpm/zlog.c +++ b/sapi/fpm/fpm/zlog.c @@ -12,6 +12,8 @@ #include <sys/time.h> #include <errno.h> +#include "php_syslog.h" + #include "zlog.h" #include "fpm.h" @@ -22,12 +24,22 @@ static int zlog_level = ZLOG_NOTICE; static int launched = 0; static const char *level_names[] = { - [ZLOG_DEBUG] = "DEBUG", - [ZLOG_NOTICE] = "NOTICE", - [ZLOG_WARNING] = "WARNING", - [ZLOG_ERROR] = "ERROR", - [ZLOG_ALERT] = "ALERT", + [ZLOG_DEBUG] = "DEBUG", + [ZLOG_NOTICE] = "NOTICE", + [ZLOG_WARNING] = "WARNING", + [ZLOG_ERROR] = "ERROR", + [ZLOG_ALERT] = "ALERT", +}; + +#ifdef HAVE_SYSLOG_H +const int syslog_priorities[] = { + [ZLOG_DEBUG] = LOG_DEBUG, + [ZLOG_NOTICE] = LOG_NOTICE, + [ZLOG_WARNING] = LOG_WARNING, + [ZLOG_ERROR] = LOG_ERR, + [ZLOG_ALERT] = LOG_ALERT, }; +#endif const char *zlog_get_level_name(int log_level) /* {{{ */ { @@ -94,18 +106,30 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* } saved_errno = errno; - if (!fpm_globals.is_child) { - gettimeofday(&tv, 0); - len = zlog_print_time(&tv, buf, buf_size); - } - if (zlog_level == ZLOG_DEBUG) { +#ifdef HAVE_SYSLOG_H + if (zlog_fd == ZLOG_SYSLOG /* && !fpm_globals.is_child */) { + len = 0; + if (zlog_level == ZLOG_DEBUG) { + len += snprintf(buf, buf_size, "[%s] %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); + } else { + len += snprintf(buf, buf_size, "[%s] ", level_names[flags & ZLOG_LEVEL_MASK]); + } + } else +#endif + { if (!fpm_globals.is_child) { - len += snprintf(buf + len, buf_size - len, "%s: pid %d, %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], getpid(), function, line); + gettimeofday(&tv, 0); + len = zlog_print_time(&tv, buf, buf_size); + } + if (zlog_level == ZLOG_DEBUG) { + if (!fpm_globals.is_child) { + len += snprintf(buf + len, buf_size - len, "%s: pid %d, %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], getpid(), function, line); + } else { + len += snprintf(buf + len, buf_size - len, "%s: %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); + } } else { - len += snprintf(buf + len, buf_size - len, "%s: %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); + len += snprintf(buf + len, buf_size - len, "%s: ", level_names[flags & ZLOG_LEVEL_MASK]); } - } else { - len += snprintf(buf + len, buf_size - len, "%s: ", level_names[flags & ZLOG_LEVEL_MASK]); } if (len > buf_size - 1) { @@ -135,9 +159,19 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* len = buf_size - 1; } - buf[len++] = '\n'; - write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len); - if (zlog_fd != STDERR_FILENO && zlog_fd > -1 && !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) { +#ifdef HAVE_SYSLOG_H + if (zlog_fd == ZLOG_SYSLOG) { + buf[len] = '\0'; + php_syslog(syslog_priorities[zlog_level], "%s", buf); + buf[len++] = '\n'; + } else +#endif + { + buf[len++] = '\n'; + write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len); + } + + if (zlog_fd != STDERR_FILENO && zlog_fd != -1 && !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) { write(STDERR_FILENO, buf, len); } } diff --git a/sapi/fpm/fpm/zlog.h b/sapi/fpm/fpm/zlog.h index a83e32902..e6a5c019a 100644 --- a/sapi/fpm/fpm/zlog.h +++ b/sapi/fpm/fpm/zlog.h @@ -19,6 +19,10 @@ size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len); void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) __attribute__ ((format(printf,4,5))); +#ifdef HAVE_SYSLOG_H +extern const int syslog_priorities[]; +#endif + enum { ZLOG_DEBUG = 1, ZLOG_NOTICE = 2, @@ -33,4 +37,8 @@ enum { #define ZLOG_SYSERROR (ZLOG_ERROR | ZLOG_HAVE_ERRNO) +#ifdef HAVE_SYSLOG_H +#define ZLOG_SYSLOG -2 +#endif + #endif diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index fe2f1a6dc..4e7952bdd 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -25,10 +25,25 @@ ;pid = run/php-fpm.pid ; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; in a local file. ; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@ ; Default Value: log/php-fpm.log ;error_log = log/php-fpm.log +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +;syslog.facility = daemon + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +;syslog.ident = php-fpm + ; Log level ; Possible Values: alert, error, warning, notice, debug ; Default Value: notice @@ -54,6 +69,13 @@ ; Default Value: 0 ;process_control_timeout = 0 +; The maximum number of processes FPM will fork. This has been design to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +; process.max = 128 + ; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. ; Default Value: yes ;daemonize = yes @@ -67,6 +89,16 @@ ; Default Value: system defined value ;rlimit_core = 0 +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +; events.mechanism = epoll + ;;;;;;;;;;;;;;;;;;;; ; Pool Definitions ; ;;;;;;;;;;;;;;;;;;;; @@ -94,6 +126,12 @@ ; Default Value: none ;prefix = /path/to/pools/$pool +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = @php_fpm_user@ +group = @php_fpm_group@ + ; The address on which to accept FastCGI requests. ; Valid syntaxes are: ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on @@ -107,14 +145,6 @@ listen = 127.0.0.1:9000 ; Set listen(2) backlog. A value of '-1' means unlimited. ; Default Value: 128 (-1 on FreeBSD and OpenBSD) ;listen.backlog = -1 - -; List of ipv4 addresses of FastCGI clients which are allowed to connect. -; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original -; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address -; must be separated by a comma. If this value is left blank, connections will be -; accepted from any ip address. -; Default Value: any -;listen.allowed_clients = 127.0.0.1 ; Set permissions for unix socket, if one is used. In Linux, read/write ; permissions must be set in order to allow connections from a web server. Many @@ -124,18 +154,21 @@ listen = 127.0.0.1:9000 ;listen.owner = @php_fpm_user@ ;listen.group = @php_fpm_group@ ;listen.mode = 0666 - -; Unix user/group of processes -; Note: The user is mandatory. If the group is not set, the default user's group -; will be used. -user = @php_fpm_user@ -group = @php_fpm_group@ + +; List of ipv4 addresses of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +;listen.allowed_clients = 127.0.0.1 ; Choose how the process manager will control the number of child processes. ; Possible Values: ; static - a fixed number (pm.max_children) of child processes; ; dynamic - the number of child processes are set dynamically based on the -; following directives: +; following directives. With this process management, there will be +; always at least 1 children. ; pm.max_children - the maximum number of children that can ; be alive at the same time. ; pm.start_servers - the number of children created on startup. @@ -147,33 +180,45 @@ group = @php_fpm_group@ ; state (waiting to process). If the number ; of 'idle' processes is greater than this ; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. ; Note: This value is mandatory. pm = dynamic ; The number of child processes to be created when pm is set to 'static' and the -; maximum number of child processes to be created when pm is set to 'dynamic'. +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. ; This value sets the limit on the number of simultaneous requests that will be ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP -; CGI. -; Note: Used when pm is set to either 'static' or 'dynamic' +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' ; Note: This value is mandatory. -pm.max_children = 50 +pm.max_children = 5 ; The number of child processes created on startup. ; Note: Used only when pm is set to 'dynamic' ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 -;pm.start_servers = 20 +pm.start_servers = 2 ; The desired minimum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' -;pm.min_spare_servers = 5 +pm.min_spare_servers = 1 ; The desired maximum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' -;pm.max_spare_servers = 35 +pm.max_spare_servers = 3 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; ; The number of requests each child process should execute before respawning. ; This can be useful to work around memory leaks in 3rd party libraries. For @@ -182,34 +227,98 @@ pm.max_children = 50 ;pm.max_requests = 500 ; The URI to view the FPM status page. If this value is not set, no URI will be -; recognized as a status page. By default, the status page shows the following -; information: -; accepted conn - the number of request accepted by the pool; +; recognized as a status page. It shows the following informations: ; pool - the name of the pool; -; process manager - static or dynamic; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; ; idle processes - the number of idle processes; ; active processes - the number of active processes; -; total processes - the number of idle + active processes. +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; ; max children reached - number of times, the process limit has been reached, ; when pm tries to start more children (works only for -; pm 'dynamic') -; The values of 'idle processes', 'active processes' and 'total processes' are -; updated each second. The value of 'accepted conn' is updated in real time. +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. ; Example output: -; accepted conn: 12073 ; pool: www ; process manager: static -; idle processes: 35 -; active processes: 65 -; total processes: 100 -; max children reached: 1 +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; ; By default the status page output is formatted as text/plain. Passing either -; 'html', 'xml' or 'json' as a query string will return the corresponding output -; syntax. Example: +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: ; http://www.foo.bar/status ; http://www.foo.bar/status?json ; http://www.foo.bar/status?html ; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: @EXPANDED_DATADIR@/fpm/status.html +; ; Note: The value must start with a leading slash (/). The value can be ; anything, but it may not be a good idea to use the .php extension or it ; may conflict with a real PHP file. @@ -292,12 +401,10 @@ pm.max_children = 50 ; Default: "%R - %u %t \"%m %r\" %s" ;access.format = %R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%% -; The timeout for serving a single request after which the worker process will -; be killed. This option should be used when the 'max_execution_time' ini option -; does not stop script execution for some reason. A value of '0' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -;request_terminate_timeout = 0 +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/$pool.log.slow ; The timeout for serving a single request after which a PHP backtrace will be ; dumped to the 'slowlog' file. A value of '0s' means 'off'. @@ -305,10 +412,12 @@ pm.max_children = 50 ; Default Value: 0 ;request_slowlog_timeout = 0 -; The log file for slow requests -; Default Value: not set -; Note: slowlog is mandatory if request_slowlog_timeout is set -;slowlog = log/$pool.log.slow +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_terminate_timeout = 0 ; Set open file descriptor rlimit. ; Default Value: system defined value @@ -341,6 +450,14 @@ pm.max_children = 50 ; process time (several ms). ; Default Value: no ;catch_workers_output = yes + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; exectute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from ; the current environment. diff --git a/sapi/fpm/status.html.in b/sapi/fpm/status.html.in new file mode 100644 index 000000000..86492d73d --- /dev/null +++ b/sapi/fpm/status.html.in @@ -0,0 +1,459 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- + $Id$ + (c) 2011 Jerome Loyet + The PHP License, version 3.01 + This is sample real-time status page for FPM. You can change it to better feet your needs. +--> + <head> + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> + <style type="text/css"> + body {background-color: #ffffff; color: #000000;} + body, td, th, h1, h2 {font-family: sans-serif;} + pre {margin: 0px; font-family: monospace;} + a:link {color: #000099; text-decoration: none; background-color: #ffffff;} + a:hover {text-decoration: underline;} + table {border-collapse: collapse;} + .center {text-align: center;} + .center table { margin-left: auto; margin-right: auto; text-align: left;} + .center th { text-align: center !important; } + td, th { border: 1px solid #000000; font-size: 75%; vertical-align: baseline;} + h1 {font-size: 150%;} + h2 {font-size: 125%;} + .p {text-align: left;} + .e {background-color: #ccccff; font-weight: bold; color: #000000;} + .h {background-color: #9999cc; font-weight: bold; color: #000000;} + + .v {background-color: #cccccc; color: #000000;} + .w {background-color: #ccccff; color: #000000;} + + .h th { + cursor: pointer; + } + img {float: right; border: 0px;} + hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000000;} + </style> + <title>PHP-FPM status page</title> + <meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" /></head> + <body> + <div class="center"> + <table border="0" cellpadding="3" width="95%"> + <tr class="h"> + <td> + <a href="http://www.php.net/"><img border="0" src="https://static.php.net/www.php.net/images/php.gif" alt="PHP Logo" /></a><h1 class="p">PHP-FPM real-time status page</h1> + </td> + </tr> + </table> + <br /> + <table border="0" cellpadding="3" width="95%"> + <tr><td class="e">Status URL</td><td class="v"><input type="text" id="url" size="45" /></td></tr> + <tr><td class="e">Ajax status</td><td class="v" id="status"></td></tr> + <tr><td class="e">Refresh Rate</td><td class="v"><input type="text" id="rate" value="1" /></td></tr> + <tr> + <td class="e">Actions</td> + <td class="v"> + <button onclick="javascript:refresh();">Manual Refresh</button> + <button id="play" onclick="javascript:playpause();">Play</button> + </td> + </tr> + </table> + <h1>Pool Status</h1> + <table border="0" cellpadding="3" width="95%" id="short"> + <tr style="display: none;"><td> </td></tr> + </table> + <h1>Active Processes status</h1> + <table border="0" cellpadding="3" width="95%" id="active"> + <tr class="h"><th>PID↓</th><th>Start Time</th><th>Start Since</th><th>Requests Served</th><th>Request Duration</th><th>Request method</th><th>Request URI</th><th>Content Length</th><th>User</th><th>Script</th></tr> + </table> + <h1>Idle Processes status</h1> + <table border="0" cellpadding="3" width="95%" id="idle"> + <tr class="h"><th>PID↓</th><th>Start Time</th><th>Start Since</th><th>Requests Served</th><th>Request Duration</th><th>Request method</th><th>Request URI</th><th>Content Length</th><th>User</th><th>Script</th><th>Last Request %CPU</th><th>Last Request Memory</th></tr> + </table> + </div> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Transitional" height="31" width="88" /> + </a> + </p> + <script type="text/javascript"> +<!-- + var xhr_object = null; + var doc_url = document.getElementById("url"); + var doc_rate = document.getElementById("rate"); + var doc_status = document.getElementById("status"); + var doc_play = document.getElementById("play"); + var doc_short = document.getElementById("short"); + var doc_active = document.getElementById("active"); + var doc_idle = document.getElementById("idle"); + var rate = 0; + var play=0; + var delay = 1000; + var order_active_index = 0; + var order_active_reverse = 0; + var order_idle_index = 0; + var order_idle_reverse = 0; + var sort_index; + var sort_order; + + doc_url.value = location.protocol + '//' + location.host + "/status?json&full"; + + ths = document.getElementsByTagName("th"); + for (var i=0; i<ths.length; i++) { + var th = ths[i]; + if (th.parentNode.className == "h") { + th.onclick = function() { order(this); return false; }; + } + } + + xhr_object = create_ajax(); + + function create_ajax() { + if (window.XMLHttpRequest) { + return new XMLHttpRequest(); + } + var names = [ + "Msxml2.XMLHTTP.6.0", + "Msxml2.XMLHTTP.3.0", + "Msxml2.XMLHTTP", + "Microsoft.XMLHTTP" + ]; + for(var i in names) + { + try { + return new ActiveXObject(names[i]); + } catch(e){} + } + alert("Browser not compatible ..."); + } + + function order(cell) { + var table; + + if (cell.constructor != HTMLTableCellElement && cell.constructor != HTMLTableHeaderCellElement) { + return; + } + + table = cell.parentNode.parentNode.parentNode; + + if (table == doc_active) { + if (order_active_index == cell.cellIndex) { + if (order_active_reverse == 0) { + cell.innerHTML = cell.innerHTML.replace(/.$/, "↑"); + order_active_reverse = 1; + } else { + cell.innerHTML = cell.innerHTML.replace(/.$/, "↓"); + order_active_reverse = 0; + } + } else { + var c = doc_active.rows[0].cells[order_active_index]; + c.innerHTML = c.innerHTML.replace(/.$/, ""); + cell.innerHTML = cell.innerHTML.replace(/$/, order_active_reverse == 0 ? "↓" : "↑"); + order_active_index = cell.cellIndex; + } + reorder(table, order_active_index, order_active_reverse); + return; + } + + if (table == doc_idle) { + if (order_idle_index == cell.cellIndex) { + if (order_idle_reverse == 0) { + cell.innerHTML = cell.innerHTML.replace(/.$/, "↑"); + order_idle_reverse = 1; + } else { + cell.innerHTML = cell.innerHTML.replace(/.$/, "↓"); + order_idle_reverse = 0; + } + } else { + var c = doc_idle.rows[0].cells[order_idle_index]; + c.innerHTML = c.innerHTML.replace(/.$/, ""); + cell.innerHTML = cell.innerHTML.replace(/$/, order_idle_reverse == 0 ? "↓" : "↑"); + order_idle_index = cell.cellIndex; + } + reorder(table, order_idle_index, order_idle_reverse); + return; + } + } + + function reorder(table, index, order) { + var rows = []; + while (table.rows.length > 1) { + rows.push(table.rows[1]); + table.deleteRow(1); + } + sort_index = index; + sort_order = order; + rows.sort(sort_table); + for (var i in rows) { + table.appendChild(rows[i]); + } + var odd = 1; + for (var i=1; i<table.rows.length; i++) { + table.rows[i].className = odd++ % 2 == 0 ? "v" : "w"; + } + return; + } + + function sort_table(a, b) { + if (a.cells[0].tagName == "TH") return -1; + if (b.cells[0].tagName == "TH") return 1; + + if (a.cells[sort_index].__search_t == 0) { /* integer */ + if (!sort_order) return a.cells[sort_index].__search_v - b.cells[sort_index].__search_v; + return b.cells[sort_index].__search_v - a.cells[sort_index].__search_v;; + } + + /* string */ + if (!sort_order) return a.cells[sort_index].__search_v.localeCompare(b.cells[sort_index].__search_v); + else return b.cells[sort_index].__search_v.localeCompare(a.cells[sort_index].__search_v); + } + + function playpause() { + rate = 0; + if (play) { + play = 0; + doc_play.innerHTML = "Play"; + doc_rate.disabled = false; + } else { + delay = parseInt(doc_rate.value); + if (!delay || delay < 1) { + doc_status.innerHTML = "Not valid 'refresh' value"; + return; + } + play = 1; + doc_rate.disabled = true; + doc_play.innerHTML = "Pause"; + setTimeout("callback()", delay * 1000); + } + } + + function refresh() { + if (xhr_object == null) return; + if (xhr_object.readyState > 0 && xhr_object.readyState < 4) { + return; /* request is running */ + } + xhr_object.open("GET", doc_url.value, true); + xhr_object.onreadystatechange = function() { + switch(xhr_object.readyState) { + case 0: + doc_status.innerHTML = "uninitialized"; + break; + case 1: + doc_status.innerHTML = "loading ..."; + break; + case 2: + doc_status.innerHTML = "loaded"; + break; + case 3: + doc_status.innerHTML = "interactive"; + break; + case 4: + doc_status.innerHTML = "complete"; + if (xhr_object.status == 200) { + fpm_status(xhr_object.responseText); + } else { + doc_status.innerHTML = "Error " + xhr_object.status; + } + break; + } + } + xhr_object.send(); + } + + function callback() { + if (!play) return; + refresh(); + setTimeout("callback()", delay * 1000); + } + + function fpm_status(txt) { + var json = null; + + while (doc_short.rows.length > 0) { + doc_short.deleteRow(0); + } + + while (doc_active.rows.length > 1) { + doc_active.deleteRow(1); + } + + while (doc_idle.rows.length > 1) { + doc_idle.deleteRow(1); + } + + try { + json = JSON.parse(txt); + } catch (e) { + doc_status.innerHTML = "Error while parsing json: '" + e + "': <br /><pre>" + txt + "</pre>"; + return; + } + + for (var key in json) { + if (key == "processes") continue; + if (key == "state") continue; + var row = doc_short.insertRow(doc_short.rows.length); + var value = json[key]; + if (key == "start time") { + value = new Date(value * 1000).toLocaleString(); + } + if (key == "start since") { + value = time_s(value); + } + var cell = row.insertCell(row.cells.length); + cell.className = "e"; + cell.innerHTML = key; + + cell = row.insertCell(row.cells.length); + cell.className = "v"; + cell.innerHTML = value; + } + + if (json.processes) { + process_full(json.processes, doc_active, "Idle", 0, 0); + reorder(doc_active, order_active_index, order_active_reverse); + + process_full(json.processes, doc_idle, "Idle", 1, 1); + reorder(doc_idle, order_idle_index, order_idle_reverse); + } + } + + function process_full(processes, table, state, equal, cpumem) { + var odd = 1; + + for (var i in processes) { + var proc = processes[i]; + if ((equal && proc.state == state) || (!equal && proc.state != state)) { + var c = odd++ % 2 == 0 ? "v" : "w"; + var row = table.insertRow(-1); + row.className = c; + row.insertCell(-1).innerHTML = proc.pid; + row.cells[row.cells.length - 1].__search_v = proc.pid; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = date(proc['start time'] * 1000);; + row.cells[row.cells.length - 1].__search_v = proc['start time']; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = time_s(proc['start since']); + row.cells[row.cells.length - 1].__search_v = proc['start since']; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = proc.requests; + row.cells[row.cells.length - 1].__search_v = proc.requests; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = time_u(proc['request duration']); + row.cells[row.cells.length - 1].__search_v = proc['request duration']; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = proc['request method']; + row.cells[row.cells.length - 1].__search_v = proc['request method']; + row.cells[row.cells.length - 1].__search_t = 1; + + row.insertCell(-1).innerHTML = proc['request uri']; + row.cells[row.cells.length - 1].__search_v = proc['request uri']; + row.cells[row.cells.length - 1].__search_t = 1; + + row.insertCell(-1).innerHTML = proc['content length']; + row.cells[row.cells.length - 1].__search_v = proc['content length']; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = proc.user; + row.cells[row.cells.length - 1].__search_v = proc.user; + row.cells[row.cells.length - 1].__search_t = 1; + + row.insertCell(-1).innerHTML = proc.script; + row.cells[row.cells.length - 1].__search_v = proc.script; + row.cells[row.cells.length - 1].__search_t = 1; + + if (cpumem) { + row.insertCell(-1).innerHTML = cpu(proc['last request cpu']); + row.cells[row.cells.length - 1].__search_v = proc['last request cpu']; + row.cells[row.cells.length - 1].__search_t = 0; + + row.insertCell(-1).innerHTML = memory(proc['last request memory']); + row.cells[row.cells.length - 1].__search_v = proc['last request memory']; + row.cells[row.cells.length - 1].__search_t = 0; + } + } + } + } + + function date(d) { + var t = new Date(d); + var r = ""; + + r += (t.getDate() < 10 ? '0' : '') + t.getDate(); + r += '/'; + r += (t.getMonth() + 1 < 10 ? '0' : '') + (t.getMonth() + 1); + r += '/'; + r += t.getFullYear(); + r += ' '; + r += (t.getHours() < 10 ? '0' : '') + t.getHours(); + r += ':'; + r += (t.getMinutes() < 10 ? '0' : '') + t.getMinutes(); + r += ':'; + r += (t.getSeconds() < 10 ? '0' : '') + t.getSeconds(); + + + return r; + } + + function cpu(c) { + if (c == 0) return 0; + return c + "%"; + } + + function memory(mem) { + if (mem == 0) return 0; + if (mem < 1024) { + return mem + "B"; + } + if (mem < 1024 * 1024) { + return mem/1024 + "KB"; + } + if (mem < 1024*1024*1024) { + return mem/1024/1024 + "MB"; + } + } + + function time_s(t) { + var r = ""; + if (t < 60) { + return t + 's'; + } + + r = (t % 60) + 's'; + t = Math.floor(t / 60); + if (t < 60) { + return t + 'm ' + r; + } + + r = (t % 60) + 'm ' + r; + t = Math.floor(t/60); + + if (t < 24) { + return t + 'h ' + r; + } + + return Math.floor(t/24) + 'd ' + (t % 24) + 'h ' + t; + } + + function time_u(t) { + var r = ""; + if (t < 1000) { + return t + 'µs' + } + + r = (t % 1000) + 'µs'; + t = Math.floor(t / 1000); + if (t < 1000) { + return t + 'ms ' + r; + } + + return time_s(Math.floor(t/1000)) + ' ' + (t%1000) + 'ms ' + r; + } +--> + </script> + </body> +</html> diff --git a/sapi/isapi/php5isapi.c b/sapi/isapi/php5isapi.c index b013ba286..9dac7d901 100644 --- a/sapi/isapi/php5isapi.c +++ b/sapi/isapi/php5isapi.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ | Ben Mansell <ben@zeus.com> (Zeus Support) | +----------------------------------------------------------------------+ */ -/* $Id: php5isapi.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: php5isapi.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #include <httpext.h> diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c index 0a2f04a28..1796f6382 100644 --- a/sapi/litespeed/lsapi_main.c +++ b/sapi/litespeed/lsapi_main.c @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: lsapi_main.c 311680 2011-05-31 22:40:42Z gwang $ */ +/* $Id: lsapi_main.c 321616 2011-12-31 18:15:06Z gwang $ */ #include "php.h" #include "SAPI.h" @@ -225,6 +225,7 @@ static int add_variable( const char * pKey, int keyLen, const char * pValue, int } +#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5) static int add_variable_magic_quote( const char * pKey, int keyLen, const char * pValue, int valLen, void * arg ) { @@ -244,6 +245,8 @@ static int add_variable_magic_quote( const char * pKey, int keyLen, const char * return 1; } +#endif + /* {{{ sapi_lsapi_register_variables */ static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC) @@ -253,15 +256,19 @@ static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC) if ( (SG(request_info).request_uri ) ) php_self = (SG(request_info).request_uri ); +#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5) if (!PG(magic_quotes_gpc)) { +#endif LSAPI_ForeachHeader( add_variable, track_vars_array ); LSAPI_ForeachEnv( add_variable, track_vars_array ); add_variable("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array ); +#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5) } else { LSAPI_ForeachHeader( add_variable_magic_quote, track_vars_array ); LSAPI_ForeachEnv( add_variable_magic_quote, track_vars_array ); add_variable_magic_quote("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array ); } +#endif php_import_environment_variables(track_vars_array TSRMLS_CC); } else { php_import_environment_variables(track_vars_array TSRMLS_CC); @@ -344,7 +351,7 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ sapi_lsapi_send_headers */ -static void sapi_lsapi_log_message(char *message) +static void sapi_lsapi_log_message(char *message TSRMLS_DC) { int len = strlen( message ); LSAPI_Write_Stderr( message, len); @@ -979,11 +986,17 @@ int main( int argc, char * argv[] ) /* LiteSpeed PHP module starts here */ +#if PHP_MAJOR_VERSION > 4 + /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO(arginfo_litespeed__void, 0) ZEND_END_ARG_INFO() /* }}} */ +#else +#define arginfo_litespeed__void NULL +#endif + PHP_FUNCTION(litespeed_request_headers); PHP_FUNCTION(litespeed_response_headers); @@ -1042,7 +1055,8 @@ PHP_FUNCTION(litespeed_request_headers) } array_init(return_value); - LSAPI_ForeachOrgHeader( add_associate_array, return_value ); + if ( lsapi_mode ) + LSAPI_ForeachOrgHeader( add_associate_array, return_value ); } /* }}} */ diff --git a/sapi/milter/php_milter.c b/sapi/milter/php_milter.c index 188aa68bb..ce39501be 100644 --- a/sapi/milter/php_milter.c +++ b/sapi/milter/php_milter.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_milter.c 314352 2011-08-06 01:22:27Z felipe $ */ +/* $Id: php_milter.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #include "php_globals.h" @@ -1111,7 +1111,7 @@ int main(int argc, char *argv[]) } SG(headers_sent) = 1; SG(request_info).no_headers = 1; - php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2011 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); php_end_ob_buffers(1 TSRMLS_CC); exit(1); break; diff --git a/sapi/nsapi/nsapi.c b/sapi/nsapi/nsapi.c index b770f2dcc..353de227f 100644 --- a/sapi/nsapi/nsapi.c +++ b/sapi/nsapi/nsapi.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: nsapi.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: nsapi.c 321634 2012-01-01 13:15:04Z felipe $ */ /* * PHP includes @@ -312,7 +312,7 @@ PHP_MSHUTDOWN_FUNCTION(nsapi) PHP_MINFO_FUNCTION(nsapi) { php_info_print_table_start(); - php_info_print_table_row(2, "NSAPI Module Revision", "$Revision: 306939 $"); + php_info_print_table_row(2, "NSAPI Module Revision", "$Revision: 321634 $"); php_info_print_table_row(2, "Server Software", system_version()); php_info_print_table_row(2, "Sub-requests with nsapi_virtual()", (nsapi_servact_service)?((zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0))?"not supported with zlib.output_compression":"enabled"):"not supported on this platform" ); @@ -727,7 +727,9 @@ static void sapi_nsapi_register_server_variables(zval *track_vars_array TSRMLS_D nsapi_free(value); php_register_variable("SERVER_SOFTWARE", system_version(), track_vars_array TSRMLS_CC); - php_register_variable("HTTPS", (security_active ? "ON" : "OFF"), track_vars_array TSRMLS_CC); + if (security_active) { + php_register_variable("HTTPS", "ON", track_vars_array TSRMLS_CC); + } php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC); /* DOCUMENT_ROOT */ diff --git a/sapi/phttpd/php_phttpd.h b/sapi/phttpd/php_phttpd.h index 0a0d2e53c..71cff9e37 100644 --- a/sapi/phttpd/php_phttpd.h +++ b/sapi/phttpd/php_phttpd.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/sapi/phttpd/phttpd.c b/sapi/phttpd/phttpd.c index 65773dda2..3aa196446 100644 --- a/sapi/phttpd/phttpd.c +++ b/sapi/phttpd/phttpd.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/sapi/pi3web/pi3web_sapi.c b/sapi/pi3web/pi3web_sapi.c index f0135af33..b099898f0 100644 --- a/sapi/pi3web/pi3web_sapi.c +++ b/sapi/pi3web/pi3web_sapi.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -21,7 +21,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: pi3web_sapi.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: pi3web_sapi.c 321634 2012-01-01 13:15:04Z felipe $ */ #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS @@ -57,7 +57,7 @@ static void php_info_pi3web(ZEND_MODULE_INFO_FUNC_ARGS) PUTS("<table border=0 cellpadding=3 cellspacing=1 width=600 align=center>\n"); PUTS("<tr><th colspan=2 bgcolor=\"" PHP_HEADER_COLOR "\">Pi3Web Server Information</th></tr>\n"); php_info_print_table_header(2, "Information Field", "Value"); - php_info_print_table_row(2, "Pi3Web SAPI module version", "$Id: pi3web_sapi.c 306939 2011-01-01 02:19:59Z felipe $"); + php_info_print_table_row(2, "Pi3Web SAPI module version", "$Id: pi3web_sapi.c 321634 2012-01-01 13:15:04Z felipe $"); php_info_print_table_row(2, "Server Name Stamp", HTTPCore_getServerStamp()); snprintf(variable_buf, 511, "%d", HTTPCore_debugEnabled()); php_info_print_table_row(2, "Debug Enabled", variable_buf); diff --git a/sapi/roxen/roxen.c b/sapi/roxen/roxen.c index 723ffdd47..1031f46e0 100644 --- a/sapi/roxen/roxen.c +++ b/sapi/roxen/roxen.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: roxen.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: roxen.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #ifdef HAVE_ROXEN @@ -438,7 +438,7 @@ static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS) { /* char buf[512]; */ php_info_print_table_start(); - php_info_print_table_row(2, "SAPI module version", "$Id: roxen.c 306939 2011-01-01 02:19:59Z felipe $"); + php_info_print_table_row(2, "SAPI module version", "$Id: roxen.c 321634 2012-01-01 13:15:04Z felipe $"); /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate()); php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile()); php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog()); diff --git a/sapi/thttpd/README b/sapi/thttpd/README index 7529b7ecf..b0245841a 100644 --- a/sapi/thttpd/README +++ b/sapi/thttpd/README @@ -1,5 +1,5 @@ README FOR THTTPD MODULE (by Sascha Schumann) -($Date: 2003-02-19 05:57:21 -0500 (Wed, 19 Feb 2003) $) +($Date: 2003-02-19 11:57:21 +0100 (Wed, 19 Feb 2003) $) This is a SAPI module for PHP 4.x supporting thttpd, the tiny, turbo, throttling HTTP server by Jef Poskanzer. diff --git a/sapi/thttpd/php_thttpd.h b/sapi/thttpd/php_thttpd.h index e5d1c56e5..39a699c3c 100644 --- a/sapi/thttpd/php_thttpd.h +++ b/sapi/thttpd/php_thttpd.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/sapi/thttpd/thttpd.c b/sapi/thttpd/thttpd.c index 0e78c49e5..adddb2dba 100644 --- a/sapi/thttpd/thttpd.c +++ b/sapi/thttpd/thttpd.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: thttpd.c 306939 2011-01-01 02:19:59Z felipe $ */ +/* $Id: thttpd.c 321634 2012-01-01 13:15:04Z felipe $ */ #include "php.h" #include "SAPI.h" diff --git a/sapi/tux/README b/sapi/tux/README index cf2a6a0a9..3a5294c77 100644 --- a/sapi/tux/README +++ b/sapi/tux/README @@ -1,5 +1,5 @@ README FOR THE TUX MODULE (by Sascha Schumann) -($Date: 2004-01-17 08:00:38 -0500 (Sat, 17 Jan 2004) $) +($Date: 2004-01-17 14:00:38 +0100 (Sat, 17 Jan 2004) $) This is a SAPI module for the TUX web-server by Ingo Molnar. diff --git a/sapi/tux/php_tux.c b/sapi/tux/php_tux.c index 8a1f44e15..cf11856f5 100644 --- a/sapi/tux/php_tux.c +++ b/sapi/tux/php_tux.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/sapi/webjames/php_webjames.h b/sapi/webjames/php_webjames.h index 1860352fc..163e753a2 100644 --- a/sapi/webjames/php_webjames.h +++ b/sapi/webjames/php_webjames.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | diff --git a/sapi/webjames/webjames.c b/sapi/webjames/webjames.c index 5a975ecd3..b7a7a2182 100644 --- a/sapi/webjames/webjames.c +++ b/sapi/webjames/webjames.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2011 The PHP Group | + | Copyright (c) 1997-2012 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | |
