From: Jérôme Loyet Date: Fri, 26 Nov 2010 13:46:15 +0000 (+0000) Subject: - Fixed bug #52501 (libevent made FPM crashed when forking -- libevent has been removed) X-Git-Tag: php-5.3.4RC2~21 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f13f4bc872a6ce82eab587366e2ec24fb005cb00;p=php - Fixed bug #52501 (libevent made FPM crashed when forking -- libevent has been removed) --- diff --git a/NEWS b/NEWS index da02f609c8..9ea0f828f8 100644 --- a/NEWS +++ b/NEWS @@ -261,6 +261,8 @@ - PHP-FPM SAPI: . Fixed inconsistent backlog default value (-1) in FPM on many systems. (fat) + . Fixed bug #52501 (libevent made FPM crashed when forking -- libevent has + been removed). (fat) . Fixed bug #52725 (gcc builtin atomic functions were sometimes used when they were not available). (fat) . Fixed bug #52693 (configuration file errors are not logged to stderr). (fat) diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index 85100dfa4b..6899ea790b 100644 --- a/sapi/fpm/config.m4 +++ b/sapi/fpm/config.m4 @@ -2,220 +2,9 @@ dnl dnl $Id$ dnl -minimum_libevent_version="1.4.11" - PHP_ARG_ENABLE(fpm,, [ --enable-fpm EXPERIMENTAL: Enable building of the fpm SAPI executable], no, no) -dnl libevent check function {{{ -dnl @synopsis AC_LIB_EVENT([MINIMUM-VERSION]) -dnl -dnl Test for the libevent library of a particular version (or newer). -dnl Source: http://svn.apache.org/repos/asf/incubator/thrift/trunk/aclocal/ax_lib_event.m4 -dnl Modified: This file was modified for autoconf-2.13 and the PHP_ARG_WITH macro. -dnl -dnl If no path to the installed libevent is given, the macro will first try -dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt, -dnl and /opt/libevent. -dnl If these all fail, it will try the $LIBEVENT_ROOT environment variable. -dnl -dnl This macro requires that #include works and defines u_char. -dnl -dnl This macro calls: -dnl AC_SUBST(LIBEVENT_CFLAGS) -dnl AC_SUBST(LIBEVENT_LIBS) -dnl -dnl And (if libevent is found): -dnl AC_DEFINE(HAVE_LIBEVENT) -dnl -dnl It also leaves the shell variables "success" and "ac_have_libevent" -dnl set to "yes" or "no". -dnl -dnl NOTE: This macro does not currently work for cross-compiling, -dnl but it can be easily modified to allow it. (grep "cross"). -dnl -dnl @category InstalledPackages -dnl @category C -dnl @version 2007-09-12 -dnl @license AllPermissive -dnl -dnl Copyright (C) 2009 David Reiss -dnl Copying and distribution of this file, with or without modification, -dnl are permitted in any medium without royalty provided the copyright -dnl notice and this notice are preserved. - -AC_DEFUN([AC_LIB_EVENT_DO_CHECK], -[ -# Save our flags. -CPPFLAGS_SAVED="$CPPFLAGS" -LDFLAGS_SAVED="$LDFLAGS" -LIBS_SAVED="$LIBS" -LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" - -# Set our flags if we are checking a specific directory. -if test -n "$ac_libevent_path" ; then - LIBEVENT_CPPFLAGS="-I$ac_libevent_path/include" - - if test -z "$PHP_LIBDIR"; then - LIBEVENT_LDFLAGS="-L$ac_libevent_path/lib" - else - LIBEVENT_LDFLAGS="-L$ac_libevent_path/$PHP_LIBDIR" - fi - - LD_LIBRARY_PATH="$ac_libevent_path/lib:$LD_LIBRARY_PATH" -else - LIBEVENT_CPPFLAGS="" - LIBEVENT_LDFLAGS="" -fi - -# Required flag for libevent. -LIBEVENT_LIBS="-levent" - -# Prepare the environment for compilation. -CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS" -LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS" -LIBS="$LIBS $LIBEVENT_LIBS" -export CPPFLAGS -export LDFLAGS -export LIBS -export LD_LIBRARY_PATH - -success=no - -# Compile, link, and run the program. This checks: -# - event.h is available for including. -# - event_get_version() is available for linking. -# - The event version string is lexicographically greater -# than the required version. -AC_TRY_RUN([ -#include -#include - -int main(int argc, char *argv[]) -{ - const char* lib_version = event_get_version(); - const char* wnt_version = "$WANT_LIBEVENT_VERSION"; - for (;;) { - /* If we reached the end of the want version. We have it. */ - if (*wnt_version == '\0' || *wnt_version == '-') { - return 0; - } - /* If the want version continues but the lib version does not, */ - /* we are missing a letter. We don't have it. */ - if (*lib_version == '\0' || *lib_version == '-') { - return 1; - } - - /* In the 1.4 version numbering style, if there are more digits */ - /* in one version than the other, that one is higher. */ - int lib_digits; - for (lib_digits = 0; - lib_version[lib_digits] >= '0' && - lib_version[lib_digits] <= '9'; - lib_digits++) - ; - int wnt_digits; - for (wnt_digits = 0; - wnt_version[wnt_digits] >= '0' && - wnt_version[wnt_digits] <= '9'; - wnt_digits++) - ; - if (lib_digits > wnt_digits) { - return 0; - } - if (lib_digits < wnt_digits) { - return 1; - } - /* If we have greater than what we want. We have it. */ - if (*lib_version > *wnt_version) { - return 0; - } - /* If we have less, we don't. */ - if (*lib_version < *wnt_version) { - return 1; - } - lib_version++; - wnt_version++; - } - return 0; -} -],[ -success=yes -]) - -# Restore flags. -CPPFLAGS="$CPPFLAGS_SAVED" -LDFLAGS="$LDFLAGS_SAVED" -LIBS="$LIBS_SAVED" -LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" -]) - -AC_DEFUN([AC_LIB_EVENT], -[ - -PHP_ARG_WITH(libevent-dir,, -[ --with-libevent-dir[=PATH] libevent install prefix, for fpm SAPI. (default: /usr/local)], /usr/local, yes) - -if test "$PHP_LIBEVENT_DIR" != "no"; then - WANT_LIBEVENT_VERSION=ifelse([$1], ,1.2,$1) - - AC_MSG_CHECKING(for libevent >= $WANT_LIBEVENT_VERSION install prefix) - - libevent_prefix=$ac_default_prefix - if test $prefix != "NONE" -a $prefix != "" -a $prefix != "no" ; then - libevent_prefix=$prefix - fi - - if test "$PHP_LIBEVENT_DIR" = "yes"; then - PHP_LIBEVENT_DIR=$libevent_prefix - fi - - if test "$PHP_LIBEVENT_DIR" != "yes" && test "$PHP_LIBEVENT_DIR" != "/usr/local"; then - dnl don't try to be too smart, check only $PHP_LIBEVENT_DIR if specified - ac_libevent_path=$PHP_LIBEVENT_DIR - AC_LIB_EVENT_DO_CHECK - if test "$success" = "no"; then - AC_MSG_ERROR([Could not find libevent >= $WANT_LIBEVENT_VERSION in $PHP_LIBEVENT_DIR]) - fi - else - dnl check default prefixes then - for ac_libevent_path in "" $PHP_LIBEVENT_DIR /usr /usr/local /opt /opt/local /opt/libevent ; do - AC_LIB_EVENT_DO_CHECK - if test "$success" = "yes"; then - break; - fi - done - fi - - if test "$success" != "yes" ; then - AC_MSG_RESULT(no) - ac_have_libevent=no - AC_MSG_ERROR([libevent >= $WANT_LIBEVENT_VERSION could not be found]) - else - AC_MSG_RESULT($ac_libevent_path) - ac_have_libevent=yes - AC_DEFINE(HAVE_LIBEVENT, 1, [define if libevent is available]) - fi - - LIBEVENT_LIBS="-levent" - - if test -n "$ac_libevent_path"; then - LIBEVENT_CFLAGS="-I$ac_libevent_path/include" - LIBEVENT_LIBS="-L$ac_libevent_path/$PHP_LIBDIR $LIBEVENT_LIBS" - LIBEVENT_PATH="$ac_libevent_path/$PHP_LIBDIR" - fi - - AC_SUBST(LIBEVENT_CFLAGS) - AC_SUBST(LIBEVENT_LIBS) - AC_SUBST(LIBEVENT_PATH) - -else - AC_MSG_ERROR([FPM requires libevent >= $WANT_LIBEVENT_VERSION. Please specify libevent install prefix with --with-libevent-dir=yes]) -fi - -]) -dnl }}} - dnl configure checks {{{ AC_DEFUN([AC_FPM_STDLIBS], [ @@ -555,22 +344,6 @@ AC_MSG_CHECKING(for FPM build) if test "$PHP_FPM" != "no"; then AC_MSG_RESULT($PHP_FPM) - AC_LIB_EVENT([$minimum_libevent_version]) - - dnl check libevent build - LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH" - export LD_LIBRARY_PATH="$LIBEVENT_PATH:$LD_LIBRARY_PATH" - - AC_MSG_CHECKING(whether libevent build works) - PHP_TEST_BUILD(event_init, [ - AC_MSG_RESULT(yes) - ], [ - AC_MSG_RESULT(no) - AC_MSG_ERROR([build test failed. Please check the config.log for details]) - ], $LIBEVENT_LIBS) - - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED" - AC_FPM_STDLIBS AC_FPM_PRCTL AC_FPM_CLOCK @@ -619,10 +392,7 @@ if test "$PHP_FPM" != "no"; then PHP_FPM_TRACE_FILES="fpm/fpm_trace.c fpm/fpm_trace_$fpm_trace_type.c" fi - PHP_FPM_CFLAGS="$LIBEVENT_CFLAGS -I$abs_srcdir/sapi/fpm" - - SAPI_EXTRA_LIBS="$LIBEVENT_LIBS" - PHP_SUBST(SAPI_EXTRA_LIBS) + PHP_FPM_CFLAGS="-I$abs_srcdir/sapi/fpm" INSTALL_IT=":" PHP_FPM_FILES="fpm/fastcgi.c \ diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c index 987e13c3ff..60e8e4ef3a 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -23,7 +23,7 @@ struct fpm_globals_s fpm_globals; -int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, struct event_base **base) /* {{{ */ +int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf) /* {{{ */ { fpm_globals.argc = argc; fpm_globals.argv = argv; @@ -40,7 +40,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, s 0 > fpm_children_init_main() || 0 > fpm_sockets_init_main() || 0 > fpm_worker_pool_init_main() || - 0 > fpm_event_init_main(base)) { + 0 > fpm_event_init_main()) { return -1; } @@ -57,7 +57,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, s /* children: return listening socket parent: never return */ -int fpm_run(int *max_requests, struct event_base *base) /* {{{ */ +int fpm_run(int *max_requests) /* {{{ */ { struct fpm_worker_pool_s *wp; @@ -65,7 +65,7 @@ int fpm_run(int *max_requests, struct event_base *base) /* {{{ */ for (wp = fpm_worker_all_pools; wp; wp = wp->next) { int is_parent; - is_parent = fpm_children_create_initial(wp, base); + is_parent = fpm_children_create_initial(wp); if (!is_parent) { goto run_child; @@ -73,7 +73,7 @@ int fpm_run(int *max_requests, struct event_base *base) /* {{{ */ } /* run event loop forever */ - fpm_event_loop(base); + fpm_event_loop(); run_child: /* only workers reach this point */ diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h index 834f4f1929..63e3bacca4 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -6,11 +6,9 @@ #define FPM_H 1 #include -#include /* for event.h below */ -#include -int fpm_run(int *max_requests, struct event_base *base); -int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, struct event_base **base); +int fpm_run(int *max_requests); +int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf); struct fpm_globals_s { pid_t parent_pid; diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index fd11be4102..499ad08e8f 100644 --- a/sapi/fpm/fpm/fpm_children.c +++ b/sapi/fpm/fpm/fpm_children.c @@ -171,7 +171,7 @@ int fpm_children_free(struct fpm_child_s *child) /* {{{ */ } /* }}} */ -void fpm_children_bury(struct event_base *base) /* {{{ */ +void fpm_children_bury() /* {{{ */ { int status; pid_t pid; @@ -201,13 +201,13 @@ void fpm_children_bury(struct event_base *base) /* {{{ */ } else if (WIFSIGNALED(status)) { const char *signame = fpm_signal_names[WTERMSIG(status)]; - const char *have_core = WCOREDUMP(status) ? " (core dumped)" : ""; + const char *have_core = WCOREDUMP(status) ? " - core dumped" : ""; if (signame == NULL) { signame = ""; } - snprintf(buf, sizeof(buf), "on signal %d %s%s", WTERMSIG(status), signame, have_core); + snprintf(buf, sizeof(buf), "on signal %d (%s%s)", WTERMSIG(status), signame, have_core); /* if it's been killed because of dynamic process management * don't restart it automaticaly @@ -277,19 +277,19 @@ void fpm_children_bury(struct event_base *base) /* {{{ */ zlog(ZLOG_WARNING, "failed processes threshold (%d in %d sec) is reached, initiating reload", fpm_global_config.emergency_restart_threshold, fpm_global_config.emergency_restart_interval); - fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET, base); + fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET); } } if (restart_child) { - fpm_children_make(wp, 1 /* in event loop */, 1, 0, base); + fpm_children_make(wp, 1 /* in event loop */, 1, 0); if (fpm_globals.is_child) { break; } } } else { - zlog(ZLOG_ALERT, "oops, unknown child exited %s", buf); + zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s", pid, buf); } } } @@ -340,15 +340,15 @@ static void fpm_child_resources_use(struct fpm_child_s *child) /* {{{ */ } /* }}} */ -static void fpm_parent_resources_use(struct fpm_child_s *child, struct event_base *base) /* {{{ */ +static void fpm_parent_resources_use(struct fpm_child_s *child) /* {{{ */ { fpm_shm_slots_parent_use_slot(child); - fpm_stdio_parent_use_pipes(child, base); + fpm_stdio_parent_use_pipes(child); fpm_child_link(child); } /* }}} */ -int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug, struct event_base *base) /* {{{ */ +int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug) /* {{{ */ { int enough = 0; pid_t pid; @@ -378,12 +378,8 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to switch (pid) { case 0 : - event_reinit(base); /* reinitialize event base after fork() */ fpm_child_resources_use(child); fpm_globals.is_child = 1; - if (in_event_loop) { - fpm_event_exit_loop(base); - } fpm_child_init(wp); return 0; @@ -398,7 +394,7 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to default : child->pid = pid; fpm_clock_get(&child->started); - fpm_parent_resources_use(child, base); + fpm_parent_resources_use(child); zlog(is_debug ? ZLOG_DEBUG : ZLOG_NOTICE, "[pool %s] child %d started", wp->config->name, (int) pid); } @@ -409,9 +405,9 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to } /* }}} */ -int fpm_children_create_initial(struct fpm_worker_pool_s *wp, struct event_base *base) /* {{{ */ +int fpm_children_create_initial(struct fpm_worker_pool_s *wp) /* {{{ */ { - return fpm_children_make(wp, 0 /* not in event loop yet */, 0, 1, base); + return fpm_children_make(wp, 0 /* not in event loop yet */, 0, 1); } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_children.h b/sapi/fpm/fpm/fpm_children.h index d881842690..4010a4f3b8 100644 --- a/sapi/fpm/fpm/fpm_children.h +++ b/sapi/fpm/fpm/fpm_children.h @@ -7,15 +7,15 @@ #include #include -#include #include "fpm_worker_pool.h" +#include "fpm_events.h" -int fpm_children_create_initial(struct fpm_worker_pool_s *wp, struct event_base *base); +int fpm_children_create_initial(struct fpm_worker_pool_s *wp); int fpm_children_free(struct fpm_child_s *child); -void fpm_children_bury(struct event_base *base); +void fpm_children_bury(); int fpm_children_init_main(); -int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug, struct event_base *base); +int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug); struct fpm_child_s; @@ -23,7 +23,7 @@ struct fpm_child_s { struct fpm_child_s *prev, *next; struct timeval started; struct fpm_worker_pool_s *wp; - struct event ev_stdout, ev_stderr; + struct fpm_event_s ev_stdout, ev_stderr; int shm_slot_i; int fd_stdout, fd_stderr; void (*tracer)(struct fpm_child_s *); diff --git a/sapi/fpm/fpm/fpm_events.c b/sapi/fpm/fpm/fpm_events.c index dcc0ce5f62..66ff393e2f 100644 --- a/sapi/fpm/fpm/fpm_events.c +++ b/sapi/fpm/fpm/fpm_events.c @@ -9,6 +9,9 @@ #include /* for putenv */ #include +#include +#include + #include "fpm.h" #include "fpm_process_ctl.h" #include "fpm_events.h" @@ -17,19 +20,43 @@ #include "fpm_signals.h" #include "fpm_children.h" #include "zlog.h" +#include "fpm_clock.h" + +#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout); + +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; + +static void fpm_event_cleanup(int which, void *arg); +static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg); +static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev); +static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev); +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_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) /* {{{ */ { - struct event_base *base = (struct event_base *)arg; - event_base_free(base); + if (fpm_event_ufds) { + free(fpm_event_ufds); + } + fpm_event_queue_destroy(&fpm_event_queue_timer); + fpm_event_queue_destroy(&fpm_event_queue_fd); } /* }}} */ -static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */ +static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ { char c; int res; - struct event_base *base = (struct event_base *)arg; + int fd = ev->fd;; do { do { @@ -46,22 +73,22 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */ switch (c) { case 'C' : /* SIGCHLD */ zlog(ZLOG_DEBUG, "received SIGCHLD"); - fpm_children_bury(base); + fpm_children_bury(); break; case 'I' : /* SIGINT */ zlog(ZLOG_DEBUG, "received SIGINT"); zlog(ZLOG_NOTICE, "Terminating ..."); - fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET, base); + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET); break; case 'T' : /* SIGTERM */ zlog(ZLOG_DEBUG, "received SIGTERM"); zlog(ZLOG_NOTICE, "Terminating ..."); - fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET, base); + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET); break; case 'Q' : /* SIGQUIT */ zlog(ZLOG_DEBUG, "received SIGQUIT"); zlog(ZLOG_NOTICE, "Finishing ..."); - fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET, base); + fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET); break; case '1' : /* SIGUSR1 */ zlog(ZLOG_DEBUG, "received SIGUSR1"); @@ -74,7 +101,7 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */ case '2' : /* SIGUSR2 */ zlog(ZLOG_DEBUG, "received SIGUSR2"); zlog(ZLOG_NOTICE, "Reloading in progress ..."); - fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET, base); + fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET); break; } @@ -86,57 +113,335 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */ } /* }}} */ -int fpm_event_init_main(struct event_base **base) /* {{{ */ +static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev) /* {{{ */ +{ + if (!ev) { + return NULL; + } + + while (queue) { + if (queue->ev == ev) { + return ev; + } + queue = queue->next; + } + + return NULL; +} +/* }}} */ + +static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */ +{ + struct fpm_event_queue_s *elt; + + if (!queue || !ev) { + return -1; + } + + if (fpm_event_queue_isset(*queue, ev)) { + return 0; + } + + if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) { + zlog(ZLOG_SYSERROR, "malloc() failed"); + return -1; + } + elt->prev = NULL; + elt->next = NULL; + elt->ev = ev; + + if (*queue) { + (*queue)->prev = elt; + elt->next = *queue; + } + *queue = elt; + + return 0; +} +/* }}} */ + +static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */ +{ + struct fpm_event_queue_s *q; + if (!queue || !ev) { + return -1; + } + q = *queue; + while (q) { + if (q->ev == ev) { + if (q->prev) { + q->prev->next = q->next; + } + if (q->next) { + q->next->prev = q->prev; + } + if (q == *queue) { + *queue = q->next; + (*queue)->prev = NULL; + } + free(q); + return 0; + } + q = q->next; + } + return -1; +} +/* }}} */ + +static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */ +{ + struct fpm_event_queue_s *q, *tmp; + + if (!queue) { + return; + } + q = *queue; + while (q) { + tmp = q; + q = q->next; + /* q->prev = NULL */ + free(tmp); + } + *queue = NULL; +} +/* }}} */ + +int fpm_event_init_main() /* {{{ */ { - *base = event_base_new(); + struct fpm_worker_pool_s *wp; + + /* 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 */ + 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); + } + } - zlog(ZLOG_DEBUG, "libevent %s: using %s", event_get_version(), event_base_get_method(*base)); + /* 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"); + return -1; + } - if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, *base)) { + zlog(ZLOG_DEBUG, "%d fds have been reserved", fpm_event_nfds_max); + + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) { return -1; } return 0; } /* }}} */ -int fpm_event_loop(struct event_base *base) /* {{{ */ +void fpm_event_loop() /* {{{ */ { - static struct event signal_fd_event; + static struct fpm_event_s signal_fd_event; + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return; + } + + fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL); + fpm_event_add(&signal_fd_event, 0); + + /* add timers */ + fpm_pctl_heartbeat(NULL, 0, NULL); + fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL); - event_set(&signal_fd_event, fpm_signals_get_fd(), EV_PERSIST | EV_READ, &fpm_got_signal, base); - event_base_set(base, &signal_fd_event); - event_add(&signal_fd_event, 0); - fpm_pctl_heartbeat(-1, 0, base); - fpm_pctl_perform_idle_server_maintenance_heartbeat(-1, 0, base); zlog(ZLOG_NOTICE, "ready to handle connections"); - event_base_dispatch(base); - return 0; + + while (1) { + struct fpm_event_queue_s *q, *q2; + struct timeval ms; + struct timeval tmp; + struct timeval now; + unsigned long int timeout; + int i, ret; + + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return; + } + + fpm_clock_get(&now); + timerclear(&ms); + + /* search in the timeout queue for the next timer to trigger */ + q = fpm_event_queue_timer; + while (q) { + if (!timerisset(&ms)) { + ms = q->ev->timeout; + } else { + if (timercmp(&q->ev->timeout, &ms, <)) { + ms = q->ev->timeout; + } + } + q = q->next; + } + + /* 1s timeout if none has been set */ + if (!timerisset(&ms) || timercmp(&ms, &now, <) || timercmp(&ms, &now, ==)) { + timeout = 1000; + } else { + timersub(&ms, &now, &tmp); + 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; + } + + /* 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; + } + } + + /* trigger timers */ + q = fpm_event_queue_timer; + while (q) { + fpm_clock_get(&now); + if (q->ev) { + if (timercmp(&now, &q->ev->timeout, >) || timercmp(&now, &q->ev->timeout, ==)) { + fpm_event_fire(q->ev); + /* sanity check */ + if (fpm_globals.parent_pid != getpid()) { + return; + } + if (q->ev->flags & FPM_EV_PERSIST) { + fpm_event_set_timeout(q->ev, now); + } else { /* delete the event */ + q2 = q; + if (q->prev) { + q->prev->next = q->next; + } + if (q->next) { + q->next->prev = q->prev; + } + if (q == fpm_event_queue_timer) { + fpm_event_queue_timer = q->next; + fpm_event_queue_timer->prev = NULL; + } + q = q->next; + free(q2); + continue; + } + } + } + q = q->next; + } + } } /* }}} */ -int fpm_event_add(int fd, struct event_base *base, struct event *ev, void (*callback)(int, short, void *), void *arg) /* {{{ */ +void fpm_event_fire(struct fpm_event_s *ev) /* {{{ */ { - event_set(ev, fd, EV_PERSIST | EV_READ, callback, arg); - event_base_set(base, ev); - return event_add(ev, 0); + if (!ev || !ev->callback) { + return; + } + + (*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg); } /* }}} */ -int fpm_event_del(struct event *ev) /* {{{ */ +int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */ { - return event_del(ev); + if (!ev || !callback || fd < -1) { + return -1; + } + memset(ev, 0, sizeof(struct fpm_event_s)); + ev->fd = fd; + ev->callback = callback; + ev->arg = arg; + ev->flags = flags; + return 0; } /* }}} */ -void fpm_event_exit_loop(struct event_base *base) /* {{{ */ +int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */ { - event_base_loopbreak(base); + struct timeval now; + struct timeval tmp; + + if (!ev) { + return -1; + } + + ev->index = -1; + + /* it's a triggered event on incoming data */ + if (ev->flags & FPM_EV_READ) { + ev->which = FPM_EV_READ; + if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != 0) { + return -1; + } + return 0; + } + + /* it's a timer event */ + ev->which = FPM_EV_TIMEOUT; + + fpm_clock_get(&now); + if (frequency >= 1000) { + tmp.tv_sec = frequency / 1000; + tmp.tv_usec = (frequency % 1000) * 1000; + } else { + tmp.tv_sec = 0; + tmp.tv_usec = frequency * 1000; + } + ev->frequency = tmp; + fpm_event_set_timeout(ev, now); + + if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) { + return -1; + } + + return 0; } /* }}} */ -void fpm_event_fire(struct event *ev) /* {{{ */ +int fpm_event_del(struct fpm_event_s *ev) /* {{{ */ { - (*ev->ev_callback)( (int) ev->ev_fd, (short) ev->ev_res, ev->ev_arg); + if (fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) { + return -1; + } + + if (fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) { + return -1; + } + + return 0; } /* }}} */ +/* }}} */ diff --git a/sapi/fpm/fpm/fpm_events.h b/sapi/fpm/fpm/fpm_events.h index 7a5a9a53b0..bec13ba5e7 100644 --- a/sapi/fpm/fpm/fpm_events.h +++ b/sapi/fpm/fpm/fpm_events.h @@ -5,12 +5,28 @@ #ifndef FPM_EVENTS_H #define FPM_EVENTS_H 1 -void fpm_event_exit_loop(struct event_base *base); -int fpm_event_loop(struct event_base *base); -int fpm_event_add(int fd, struct event_base *base, struct event *ev, void (*callback)(int, short, void *), void *arg); -int fpm_event_del(struct event *ev); -void fpm_event_fire(struct event *ev); -int fpm_event_init_main(struct event_base **base); +#define FPM_EV_TIMEOUT (1 << 0) +#define FPM_EV_READ (1 << 1) +#define FPM_EV_PERSIST (1 << 2) +#define fpm_event_set_timer(ev, flags, cb, arg) fpm_event_set((ev), -1, (flags), (cb), (arg)) + +struct fpm_event_s { + int fd; /* not set with FPM_EV_TIMEOUT */ + struct timeval timeout; /* next time to trigger */ + struct timeval frequency; + void (*callback)(struct fpm_event_s *, short, void *); + void *arg; + int flags; + int index; /* index of the fd in the ufds array */ + short which; /* type of event */ +}; + +void fpm_event_loop(); +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); #endif diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index a0672fd017..8f0d760074 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -168,7 +168,6 @@ typedef struct _php_cgi_globals_struct { HashTable user_config_cache; char *error_header; char *fpm_config; - struct event_base *event_base; } php_cgi_globals_struct; /* {{{ user_config_cache @@ -1780,11 +1779,11 @@ consult the installation file that came with this distribution, or visit \n\ } } - if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, test_conf, &CGIG(event_base))) { + if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, test_conf)) { return FAILURE; } - fcgi_fd = fpm_run(&max_requests, CGIG(event_base)); + fcgi_fd = fpm_run(&max_requests); parent = 0; fcgi_set_is_fastcgi(1); diff --git a/sapi/fpm/fpm/fpm_process_ctl.c b/sapi/fpm/fpm/fpm_process_ctl.c index 367c041b3d..badda14082 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.c +++ b/sapi/fpm/fpm/fpm_process_ctl.c @@ -49,29 +49,18 @@ static void fpm_pctl_cleanup(int which, void *arg) /* {{{ */ } /* }}} */ -static struct event pctl_event; +static struct fpm_event_s pctl_event; -static void fpm_pctl_action(int fd, short which, void *arg) /* {{{ */ +static void fpm_pctl_action(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ { - struct event_base *base = (struct event_base *)arg; - - evtimer_del(&pctl_event); - memset(&pctl_event, 0, sizeof(pctl_event)); - fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT, base); + fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT); } /* }}} */ -static int fpm_pctl_timeout_set(int sec, struct event_base *base) /* {{{ */ +static int fpm_pctl_timeout_set(int sec) /* {{{ */ { - struct timeval tv = { .tv_sec = sec, .tv_usec = 0 }; - - if (evtimer_initialized(&pctl_event)) { - evtimer_del(&pctl_event); - } - - evtimer_set(&pctl_event, &fpm_pctl_action, base); - event_base_set(base, &pctl_event); - evtimer_add(&pctl_event, &tv); + fpm_event_set_timer(&pctl_event, 0, &fpm_pctl_action, NULL); + fpm_event_add(&pctl_event, sec * 1000); return 0; } /* }}} */ @@ -181,7 +170,7 @@ static void fpm_pctl_kill_all(int signo) /* {{{ */ } /* }}} */ -static void fpm_pctl_action_next(struct event_base *base) /* {{{ */ +static void fpm_pctl_action_next() /* {{{ */ { int sig, timeout; @@ -207,11 +196,11 @@ static void fpm_pctl_action_next(struct event_base *base) /* {{{ */ fpm_pctl_kill_all(sig); fpm_signal_sent = sig; - fpm_pctl_timeout_set(timeout, base); + fpm_pctl_timeout_set(timeout); } /* }}} */ -void fpm_pctl(int new_state, int action, struct event_base *base) /* {{{ */ +void fpm_pctl(int new_state, int action) /* {{{ */ { switch (action) { case FPM_PCTL_ACTION_SET : @@ -243,7 +232,7 @@ void fpm_pctl(int new_state, int action, struct event_base *base) /* {{{ */ /* fall down */ case FPM_PCTL_ACTION_TIMEOUT : - fpm_pctl_action_next(base); + fpm_pctl_action_next(); break; case FPM_PCTL_ACTION_LAST_CHILD_EXITED : fpm_pctl_action_last(); @@ -259,14 +248,14 @@ int fpm_pctl_can_spawn_children() /* {{{ */ } /* }}} */ -int fpm_pctl_child_exited(struct event_base *base) /* {{{ */ +int fpm_pctl_child_exited() /* {{{ */ { if (fpm_state == FPM_PCTL_STATE_NORMAL) { return 0; } if (!fpm_globals.running_children) { - fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED, base); + fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED); } return 0; } @@ -318,7 +307,7 @@ static void fpm_pctl_check_request_timeout(struct timeval *now) /* {{{ */ } /* }}} */ -static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct event_base *base) /* {{{ */ +static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ */ { struct fpm_worker_pool_s *wp; @@ -396,7 +385,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct } wp->warn_max_children = 0; - fpm_children_make(wp, 1, children_to_fork, 1, base); + fpm_children_make(wp, 1, children_to_fork, 1); /* if it's a child, stop here without creating the next event * this event is reserved to the master process @@ -418,37 +407,40 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct } /* }}} */ -void fpm_pctl_heartbeat(int fd, short which, void *arg) /* {{{ */ +void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ { - static struct event heartbeat; - struct timeval tv = { .tv_sec = 0, .tv_usec = 130000 }; + static struct fpm_event_s heartbeat; struct timeval now; - struct event_base *base = (struct event_base *)arg; - if (which == EV_TIMEOUT) { - evtimer_del(&heartbeat); + if (fpm_globals.parent_pid != getpid()) { + return; /* sanity check */ + } + + if (which == FPM_EV_TIMEOUT) { fpm_clock_get(&now); fpm_pctl_check_request_timeout(&now); + return; } - evtimer_set(&heartbeat, &fpm_pctl_heartbeat, base); - event_base_set(base, &heartbeat); - evtimer_add(&heartbeat, &tv); + /* first call without setting to initialize the timer */ + fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_heartbeat, NULL); + fpm_event_add(&heartbeat, FPM_PCTL_HEARTBEAT); } /* }}} */ -void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which, void *arg) /* {{{ */ +void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ { - static struct event heartbeat; - struct timeval tv = { .tv_sec = 0, .tv_usec = FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT }; + static struct fpm_event_s heartbeat; struct timeval now; - struct event_base *base = (struct event_base *)arg; - if (which == EV_TIMEOUT) { - evtimer_del(&heartbeat); + if (fpm_globals.parent_pid != getpid()) { + return; /* sanity check */ + } + + if (which == FPM_EV_TIMEOUT) { fpm_clock_get(&now); if (fpm_pctl_can_spawn_children()) { - fpm_pctl_perform_idle_server_maintenance(&now, base); + fpm_pctl_perform_idle_server_maintenance(&now); /* if it's a child, stop here without creating the next event * this event is reserved to the master process @@ -457,11 +449,12 @@ void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which, voi return; } } + return; } - evtimer_set(&heartbeat, &fpm_pctl_perform_idle_server_maintenance_heartbeat, base); - event_base_set(base, &heartbeat); - evtimer_add(&heartbeat, &tv); + /* first call without setting which to initialize the timer */ + fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_perform_idle_server_maintenance_heartbeat, NULL); + fpm_event_add(&heartbeat, FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT); } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_process_ctl.h b/sapi/fpm/fpm/fpm_process_ctl.h index 0c8801f69b..36577097cb 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.h +++ b/sapi/fpm/fpm/fpm_process_ctl.h @@ -5,18 +5,22 @@ #ifndef FPM_PROCESS_CTL_H #define FPM_PROCESS_CTL_H 1 +#include "fpm_events.h" + /* spawn max 32 children at once */ #define FPM_MAX_SPAWN_RATE (32) -/* 1s (in µs here) heatbeat for idle server maintenance */ -#define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000000) +/* 1s (in ms) heartbeat for idle server maintenance */ +#define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000) +/* 130ms heartbeat for pctl */ +#define FPM_PCTL_HEARTBEAT (130) struct fpm_child_s; -void fpm_pctl(int new_state, int action, struct event_base *base); +void fpm_pctl(int new_state, int action); int fpm_pctl_can_spawn_children(); int fpm_pctl_kill(pid_t pid, int how); -void fpm_pctl_heartbeat(int fd, short which, void *arg); -void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which, void *arg); +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); int fpm_pctl_child_exited(); int fpm_pctl_init_main(); diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index e6ecf1a6b5..571f3074b5 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -71,18 +71,30 @@ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ } /* }}} */ -static void fpm_stdio_child_said(int fd, short which, void *arg) /* {{{ */ +static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ { static const int max_buf_size = 1024; + int fd = ev->fd; char buf[max_buf_size]; - struct fpm_child_s *child = arg; - int is_stdout = fd == child->fd_stdout; - struct event *ev = is_stdout ? &child->ev_stdout : &child->ev_stderr; + struct fpm_child_s *child; + int is_stdout; + struct fpm_event_s *event; int fifo_in = 1, fifo_out = 1; int is_last_message = 0; int in_buf = 0; int res; + if (!arg) { + return; + } + child = (struct fpm_child_s *)arg; + is_stdout = (fd == child->fd_stdout); + if (is_stdout) { + event = &child->ev_stdout; + } else { + event = &child->ev_stderr; + } + while (fifo_in || fifo_out) { if (fifo_in) { res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf); @@ -96,7 +108,7 @@ static void fpm_stdio_child_said(int fd, short which, void *arg) /* {{{ */ zlog(ZLOG_SYSERROR, "read() failed"); } - fpm_event_del(ev); + fpm_event_del(event); is_last_message = 1; if (is_stdout) { @@ -183,7 +195,7 @@ int fpm_stdio_prepare_pipes(struct fpm_child_s *child) /* {{{ */ } /* }}} */ -int fpm_stdio_parent_use_pipes(struct fpm_child_s *child, struct event_base *base) /* {{{ */ +int fpm_stdio_parent_use_pipes(struct fpm_child_s *child) /* {{{ */ { if (0 == child->wp->config->catch_workers_output) { /* not required */ return 0; @@ -195,8 +207,11 @@ int fpm_stdio_parent_use_pipes(struct fpm_child_s *child, struct event_base *bas child->fd_stdout = fd_stdout[0]; child->fd_stderr = fd_stderr[0]; - fpm_event_add(child->fd_stdout, base, &child->ev_stdout, fpm_stdio_child_said, child); - fpm_event_add(child->fd_stderr, base, &child->ev_stderr, fpm_stdio_child_said, child); + fpm_event_set(&child->ev_stdout, child->fd_stdout, FPM_EV_READ, fpm_stdio_child_said, child); + fpm_event_add(&child->ev_stdout, 0); + + fpm_event_set(&child->ev_stderr, child->fd_stderr, FPM_EV_READ, fpm_stdio_child_said, child); + fpm_event_add(&child->ev_stderr, 0); return 0; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_stdio.h b/sapi/fpm/fpm/fpm_stdio.h index 5d53a26e88..d3d61e46be 100644 --- a/sapi/fpm/fpm/fpm_stdio.h +++ b/sapi/fpm/fpm/fpm_stdio.h @@ -12,7 +12,7 @@ int fpm_stdio_init_final(); int fpm_stdio_init_child(struct fpm_worker_pool_s *wp); int fpm_stdio_prepare_pipes(struct fpm_child_s *child); void fpm_stdio_child_use_pipes(struct fpm_child_s *child); -int fpm_stdio_parent_use_pipes(struct fpm_child_s *child, struct event_base *base); +int fpm_stdio_parent_use_pipes(struct fpm_child_s *child); int fpm_stdio_discard_pipes(struct fpm_child_s *child); int fpm_stdio_open_error_log(int reopen); diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index 4b2b517313..314b7e5c5e 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -268,6 +268,8 @@ pm.max_children = 50 ; Redirect worker stdout and stderr into main error log. If not set, stdout and ; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). ; Default Value: no ;catch_workers_output = yes