From 523fd83aee7e8250b88029d0ef0c4ecfd7750147 Mon Sep 17 00:00:00 2001 From: Martin Keegan Date: Sun, 22 Apr 2012 21:15:18 +0100 Subject: [PATCH 1/2] Allow FCGI worker processes to have CPU and RAM limits imposed --- sapi/cgi/cgi_main.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 56c736f5ccbd..d84f3090fe7e 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -116,6 +116,10 @@ static int exit_signal = 0; /* Is Parent waiting for children to exit */ static int parent_waiting = 0; +/* CPU seconds and memory limits for worker processes */ +static int rlimit_cpu = 0; +static int rlimit_as = 0; + /** * Process group */ @@ -1469,6 +1473,22 @@ static zend_module_entry cgi_module_entry = { STANDARD_MODULE_PROPERTIES }; +void set_worker_rlimits(void) +{ + struct rlimit rlim; + + if (rlimit_cpu > 0) { + rlim.rlim_cur = rlimit_cpu; + rlim.rlim_max = rlimit_cpu; + setrlimit(RLIMIT_CPU, &rlim); + } + if (rlimit_as > 0) { + rlim.rlim_cur = rlimit_as; + rlim.rlim_max = rlimit_as; + setrlimit(RLIMIT_AS, &rlim); + } +} + /* {{{ main */ int main(int argc, char *argv[]) @@ -1693,6 +1713,22 @@ consult the installation file that came with this distribution, or visit \n\ } } + if (getenv("PHP_FCGI_RLIMIT_CPU")) { + rlimit_cpu = atoi(getenv("PHP_FCGI_RLIMIT_CPU")); + if (rlimit_cpu < 0) { + fprintf(stderr, "PHP_FCGI_RLIMIT_CPU is not valid\n"); + return FAILURE; + } + } + + if (getenv("PHP_FCGI_RLIMIT_AS")) { + rlimit_as = atoi(getenv("PHP_FCGI_RLIMIT_AS")); + if (rlimit_as < 0) { + fprintf(stderr, "PHP_FCGI_RLIMIT_AS is not valid\n"); + return FAILURE; + } + } + /* make php call us to get _ENV vars */ php_php_import_environment_variables = php_import_environment_variables; php_import_environment_variables = cgi_php_import_environment_variables; @@ -1761,6 +1797,7 @@ consult the installation file that came with this distribution, or visit \n\ sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); + set_worker_rlimits(); break; case -1: perror("php (pre-forking)"); From 19b5977365fde03e3cb583158ae58bfa7711c0e1 Mon Sep 17 00:00:00 2001 From: Martin Keegan Date: Mon, 23 Apr 2012 00:08:26 +0100 Subject: [PATCH 2/2] Allow FPM to set memory and CPU limits on its worker processes --- sapi/fpm/fpm/fpm_conf.c | 8 ++++++++ sapi/fpm/fpm/fpm_conf.h | 4 ++++ sapi/fpm/fpm/fpm_unix.c | 20 ++++++++++++++++++++ sapi/fpm/php-fpm.conf.in | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index 304076d35eb9..a16226e8044b 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -95,6 +95,8 @@ static struct ini_value_parser_s ini_fpm_global_options[] = { { "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) }, + { "rlimit_cpu", &fpm_conf_set_rlimit_core, GO(rlimit_cpu) }, + { "rlimit_as", &fpm_conf_set_rlimit_core, GO(rlimit_as) }, { "events.mechanism", &fpm_conf_set_string, GO(events_mechanism) }, { 0, 0, 0 } }; @@ -129,6 +131,8 @@ static struct ini_value_parser_s ini_fpm_pool_options[] = { { "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) }, + { "rlimit_cpu", &fpm_conf_set_rlimit_core, WPO(rlimit_cpu) }, + { "rlimit_as", &fpm_conf_set_rlimit_core, WPO(rlimit_as) }, { "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) }, @@ -1488,6 +1492,8 @@ static void fpm_conf_dump() /* {{{ */ 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, "\trlimit_cpu = %d", fpm_global_config.rlimit_cpu); + zlog(ZLOG_NOTICE, "\trlimit_as = %d", fpm_global_config.rlimit_as); zlog(ZLOG_NOTICE, "\tevents.mechanism = %s", fpm_event_machanism_name()); zlog(ZLOG_NOTICE, " "); @@ -1521,6 +1527,8 @@ static void fpm_conf_dump() /* {{{ */ 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, "\trlimit_cpu = %d", wp->config->rlimit_cpu); + zlog(ZLOG_NOTICE, "\trlimit_as = %d", wp->config->rlimit_as); 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)); diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h index 9fbd5064c06b..69cec659566f 100644 --- a/sapi/fpm/fpm/fpm_conf.h +++ b/sapi/fpm/fpm/fpm_conf.h @@ -38,6 +38,8 @@ struct fpm_global_config_s { int daemonize; int rlimit_files; int rlimit_core; + int rlimit_cpu; + int rlimit_as; char *events_mechanism; }; @@ -74,6 +76,8 @@ struct fpm_worker_pool_config_s { int request_terminate_timeout; int rlimit_files; int rlimit_core; + int rlimit_cpu; + int rlimit_as; char *chroot; char *chdir; int catch_workers_output; diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index 17d0b8125cc5..a7043744cac7 100644 --- a/sapi/fpm/fpm/fpm_unix.c +++ b/sapi/fpm/fpm/fpm_unix.c @@ -165,6 +165,26 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ } } + if (wp->config->rlimit_cpu) { + struct rlimit r; + + r.rlim_max = r.rlim_cur = wp->config->rlimit_cpu == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_cpu; + + if (0 > setrlimit(RLIMIT_CPU, &r)) { + zlog(ZLOG_SYSERROR, "[pool %s] failed to set rlimit_cpu for this pool. Please check your system limits or decrease rlimit_cpu. setrlimit(RLIMIT_CPU, %d)", wp->config->name, wp->config->rlimit_cpu); + } + } + + if (wp->config->rlimit_as) { + struct rlimit r; + + r.rlim_max = r.rlim_cur = wp->config->rlimit_as == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_as; + + if (0 > setrlimit(RLIMIT_AS, &r)) { + zlog(ZLOG_SYSERROR, "[pool %s] failed to set rlimit_as for this pool. Please check your system limits or decrease rlimit_as. setrlimit(RLIMIT_AS, %d)", wp->config->name, wp->config->rlimit_as); + } + } + if (is_root && wp->config->chroot && *wp->config->chroot) { if (0 > chroot(wp->config->chroot)) { zlog(ZLOG_SYSERROR, "[pool %s] failed to chroot(%s)", wp->config->name, wp->config->chroot); diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index 845eae75e73a..ffaed6791d0d 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -89,6 +89,16 @@ ; Default Value: system defined value ;rlimit_core = 0 +; Set max CPU usage in seconds; (see setrlimit(2)) +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_cpu = unlimited + +; Set max memory usage in bytes; (see setrlimit(2)) +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_as = unlimited + ; Specify the event mechanism FPM will use. The following is available: ; - select (any POSIX os) ; - poll (any POSIX os)