diff options
Diffstat (limited to 'sapi/fpm')
40 files changed, 1547 insertions, 730 deletions
diff --git a/sapi/fpm/Makefile.frag b/sapi/fpm/Makefile.frag index 0f1964ee6..0859ef10c 100644 --- a/sapi/fpm/Makefile.frag +++ b/sapi/fpm/Makefile.frag @@ -22,7 +22,7 @@ install-fpm: install-sapi @$(INSTALL_DATA) sapi/fpm/php-fpm.conf $(INSTALL_ROOT)$(sysconfdir)/php-fpm.conf.default || : - @echo "Installing PHP FPM man page: $(INSTALL_ROOT)$(mandir)/man1/" - @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 - @$(INSTALL_DATA) sapi/fpm/php-fpm.1 $(INSTALL_ROOT)$(mandir)/man1/php-fpm$(program_suffix).1 + @echo "Installing PHP FPM man page: $(INSTALL_ROOT)$(mandir)/man8/" + @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man8 + @$(INSTALL_DATA) sapi/fpm/php-fpm.8 $(INSTALL_ROOT)$(mandir)/man8/php-fpm$(program_suffix).8 diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index 0cefd968d..6899ea790 100644 --- a/sapi/fpm/config.m4 +++ b/sapi/fpm/config.m4 @@ -2,225 +2,13 @@ dnl dnl $Id$ dnl -fpm_version="0.6.5" -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 <sys/types.h> 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 <sys/types.h> -#include <event.h> - -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], [ - AC_CHECK_FUNCS(setenv clearenv) + AC_CHECK_FUNCS(setenv clearenv setproctitle) AC_SEARCH_LIBS(socket, socket) AC_SEARCH_LIBS(inet_addr, nsl) @@ -499,25 +287,69 @@ AC_DEFUN([AC_FPM_TRACE], fi ]) + +AC_DEFUN([AC_FPM_BUILTIN_ATOMIC], +[ + AC_MSG_CHECKING([if gcc supports __sync_bool_compare_and_swap]) + AC_TRY_LINK(, + [ + int variable = 1; + return (__sync_bool_compare_and_swap(&variable, 1, 2) + && __sync_add_and_fetch(&variable, 1)) ? 1 : 0; + ], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Define to 1 if gcc supports __sync_bool_compare_and_swap() a.o.]) + ], + [ + AC_MSG_RESULT([no]) + ]) +]) + +AC_DEFUN([AC_FPM_LQ], +[ + have_lq=no + + AC_MSG_CHECKING([for TCP_INFO]) + + AC_TRY_COMPILE([ #include <netinet/tcp.h> ], [struct tcp_info ti; int x = TCP_INFO;], [ + have_lq=tcp_info + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) + + if test "$have_lq" = "tcp_info"; then + AC_DEFINE([HAVE_LQ_TCP_INFO], 1, [do we have TCP_INFO?]) + fi + + if test "$have_lq" = "no" ; then + AC_MSG_CHECKING([for SO_LISTENQLEN]) + + AC_TRY_COMPILE([ #include <sys/socket.h> ], [int x = SO_LISTENQLIMIT; int y = SO_LISTENQLEN;], [ + have_lq=so_listenq + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ]) + + if test "$have_lq" = "tcp_info"; then + AC_DEFINE([HAVE_LQ_SO_LISTENQ], 1, [do we have SO_LISTENQxxx?]) + fi + fi +]) dnl }}} AC_MSG_CHECKING(for FPM build) if test "$PHP_FPM" != "no"; then AC_MSG_RESULT($PHP_FPM) - AC_LIB_EVENT([$minimum_libevent_version]) - - PHP_ADD_LIBRARY_WITH_PATH(event, $LIBEVENT_PATH) - - PHP_TEST_BUILD(event_init, [ ], [ - AC_MSG_RESULT(no) - AC_MSG_ERROR([build test failed. Please check the config.log for details.]) - ], $LIBEVENT_LIBS) - AC_FPM_STDLIBS AC_FPM_PRCTL AC_FPM_CLOCK AC_FPM_TRACE + AC_FPM_BUILTIN_ATOMIC + AC_FPM_LQ PHP_ARG_WITH(fpm-user,, [ --with-fpm-user[=USER] Set the user for php-fpm to run as. (default: nobody)], nobody, no) @@ -538,19 +370,19 @@ if test "$PHP_FPM" != "no"; then php_fpm_group="$PHP_FPM_GROUP" fi - PHP_SUBST_OLD(fpm_version) PHP_SUBST_OLD(php_fpm_user) PHP_SUBST_OLD(php_fpm_group) php_fpm_sysconfdir=`eval echo $sysconfdir` PHP_SUBST_OLD(php_fpm_sysconfdir) php_fpm_localstatedir=`eval echo $localstatedir` PHP_SUBST_OLD(php_fpm_localstatedir) + php_fpm_prefix=`eval echo $prefix` + PHP_SUBST_OLD(php_fpm_prefix) - AC_DEFINE_UNQUOTED(PHP_FPM_VERSION, "$fpm_version", [fpm version]) 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.1) + PHP_OUTPUT(sapi/fpm/php-fpm.conf sapi/fpm/init.d.php-fpm sapi/fpm/php-fpm.8) PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/sapi/fpm/Makefile.frag], [$abs_srcdir/sapi/fpm], [sapi/fpm]) SAPI_FPM_PATH=sapi/fpm/php-fpm @@ -560,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 34292b5d4..17a215c88 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -23,23 +23,26 @@ struct fpm_globals_s fpm_globals; -int fpm_init(int argc, char **argv, char *config, 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; - fpm_globals.config = config; + if (config && *config) { + fpm_globals.config = strdup(config); + } + fpm_globals.prefix = prefix; - if (0 > fpm_php_init_main() || + if (0 > fpm_php_init_main() || 0 > fpm_stdio_init_main() || - 0 > fpm_conf_init_main() || + 0 > fpm_conf_init_main(test_conf) || 0 > fpm_unix_init_main() || + 0 > fpm_pctl_init_main() || 0 > fpm_env_init_main() || 0 > fpm_signals_init_main() || - 0 > fpm_pctl_init_main() || 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; } @@ -47,7 +50,8 @@ int fpm_init(int argc, char **argv, char *config, struct event_base **base) /* { return -1; } - zlog(ZLOG_STUFF, ZLOG_NOTICE, "fpm is running, pid %d", (int) fpm_globals.parent_pid); + fpm_stdio_init_final(); + zlog(ZLOG_NOTICE, "fpm is running, pid %d", (int) fpm_globals.parent_pid); return 0; } @@ -55,7 +59,7 @@ int fpm_init(int argc, char **argv, char *config, struct event_base **base) /* { /* 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; @@ -63,7 +67,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; @@ -71,7 +75,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 ba4390448..63e3bacca 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -6,17 +6,16 @@ #define FPM_H 1 #include <unistd.h> -#include <sys/types.h> /* for event.h below */ -#include <event.h> -int fpm_run(int *max_requests, struct event_base *base); -int fpm_init(int argc, char **argv, char *config, 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; int argc; char **argv; char *config; + char *prefix; int running_children; int error_log_fd; int log_level; diff --git a/sapi/fpm/fpm/fpm_atomic.h b/sapi/fpm/fpm/fpm_atomic.h index 8c287ddfb..638bafddc 100644 --- a/sapi/fpm/fpm/fpm_atomic.h +++ b/sapi/fpm/fpm/fpm_atomic.h @@ -12,7 +12,19 @@ #endif #include <sched.h> -#if ( __i386__ || __i386 ) +#ifdef HAVE_BUILTIN_ATOMIC + +/** + * all the cases below (as provided by upstream) define: + * word as atomic_int_t, and + * unsigned word as atomic_uint_t + * and only use volatile atomic_uint_t as atomic_t + */ + +typedef volatile unsigned long atomic_t; +#define atomic_cmp_set(a,b,c) __sync_bool_compare_and_swap(a,b,c) + +#elif ( __i386__ || __i386 ) typedef int32_t atomic_int_t; typedef uint32_t atomic_uint_t; @@ -83,6 +95,8 @@ typedef uint32_t atomic_uint_t; #elif ( __sparc__ || __sparc ) /* Marcin Ochab */ +#if (__sparcv9 || __sparcv9__) + #if (__arch64__ || __arch64) typedef uint64_t atomic_uint_t; typedef volatile atomic_uint_t atomic_t; @@ -119,9 +133,13 @@ static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, at /* }}} */ #endif +#else /* #if (__sparcv9 || __sparcv9__) */ +#error Sparc v8 and predecessors are not and will not be supported (see bug report 53310) +#endif /* #if (__sparcv9 || __sparcv9__) */ + #else -#error unsupported processor. please write a patch and send it to me +#error Unsupported processor. Please open a bug report (bugs.php.net). #endif diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index d303cfb03..499ad08e8 100644 --- a/sapi/fpm/fpm/fpm_children.c +++ b/sapi/fpm/fpm/fpm_children.c @@ -152,7 +152,7 @@ static void fpm_child_init(struct fpm_worker_pool_s *wp) /* {{{ */ 0 > fpm_env_init_child(wp) || 0 > fpm_php_init_child(wp)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] child failed to initialize", wp->config->name); + zlog(ZLOG_ERROR, "[pool %s] child failed to initialize", wp->config->name); exit(255); } } @@ -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,18 +201,18 @@ 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 */ - if (child && child->idle_kill && WTERMSIG(status) == SIGTERM) { + if (child && child->idle_kill && WTERMSIG(status) == SIGQUIT) { restart_child = 0; } @@ -221,7 +221,7 @@ void fpm_children_bury(struct event_base *base) /* {{{ */ } } else if (WIFSTOPPED(status)) { - zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d stopped for tracing", (int) pid); + zlog(ZLOG_NOTICE, "child %d stopped for tracing", (int) pid); if (child && child->tracer) { child->tracer(child); @@ -246,9 +246,9 @@ void fpm_children_bury(struct event_base *base) /* {{{ */ if (!fpm_pctl_can_spawn_children()) { severity = ZLOG_DEBUG; } - zlog(ZLOG_STUFF, severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", child->wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); + zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", child->wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); } else { - zlog(ZLOG_STUFF, ZLOG_DEBUG, "[pool %s] child %d has been killed by the process managment after %ld.%06d seconds from start", child->wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); + zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process managment after %ld.%06d seconds from start", child->wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); } fpm_child_close(child, 1 /* in event_loop */); @@ -275,21 +275,21 @@ void fpm_children_bury(struct event_base *base) /* {{{ */ if (restart_condition) { - zlog(ZLOG_STUFF, 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); + 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_STUFF, ZLOG_ALERT, "oops, unknown child exited %s", buf); + zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s", pid, buf); } } } @@ -302,7 +302,7 @@ static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) / c = fpm_child_alloc(); if (!c) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] malloc failed", wp->config->name); + zlog(ZLOG_ERROR, "[pool %s] malloc failed", wp->config->name); return 0; } @@ -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,17 +378,13 @@ 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; case -1 : - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed"); + zlog(ZLOG_SYSERROR, "fork() failed"); enough = 1; fpm_resources_discard(child); @@ -398,9 +394,9 @@ 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(ZLOG_STUFF, is_debug ? ZLOG_DEBUG : ZLOG_NOTICE, "[pool %s] child %d started", wp->config->name, (int) pid); + 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 d88184269..4010a4f3b 100644 --- a/sapi/fpm/fpm/fpm_children.h +++ b/sapi/fpm/fpm/fpm_children.h @@ -7,15 +7,15 @@ #include <sys/time.h> #include <sys/types.h> -#include <event.h> #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_clock.c b/sapi/fpm/fpm/fpm_clock.c index 3eb515943..66751b81b 100644 --- a/sapi/fpm/fpm/fpm_clock.c +++ b/sapi/fpm/fpm/fpm_clock.c @@ -37,7 +37,7 @@ int fpm_clock_get(struct timeval *tv) /* {{{ */ struct timespec ts; if (0 > clock_gettime(CLOCK_MONOTONIC, &ts)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "clock_gettime() failed"); + zlog(ZLOG_SYSERROR, "clock_gettime() failed"); return -1; } @@ -69,7 +69,7 @@ int fpm_clock_init() /* {{{ */ ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &mach_clock); if (ret != KERN_SUCCESS) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "host_get_clock_service() failed: %s", mach_error_string(ret)); + zlog(ZLOG_ERROR, "host_get_clock_service() failed: %s", mach_error_string(ret)); return -1; } @@ -77,7 +77,7 @@ int fpm_clock_init() /* {{{ */ ret = clock_get_time(mach_clock, &aTime); if (ret != KERN_SUCCESS) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret)); + zlog(ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret)); return -1; } @@ -93,7 +93,7 @@ int fpm_clock_get(struct timeval *tv) /* {{{ */ ret = clock_get_time(mach_clock, &aTime); if (ret != KERN_SUCCESS) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret)); + zlog(ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret)); return -1; } diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index 4590155c7..f38227c2f 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -52,50 +52,54 @@ 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); -struct fpm_global_config_s fpm_global_config = { 0, 0, 0, 1, NULL, NULL}; +struct fpm_global_config_s fpm_global_config = { .daemonize = 1 }; 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; +#define GO(field) offsetof(struct fpm_global_config_s, field) +#define WPO(field) offsetof(struct fpm_worker_pool_config_s, field) + static struct ini_value_parser_s ini_fpm_global_options[] = { - { "emergency_restart_threshold", &fpm_conf_set_integer, offsetof(struct fpm_global_config_s, emergency_restart_threshold) }, - { "emergency_restart_interval", &fpm_conf_set_time, offsetof(struct fpm_global_config_s, emergency_restart_interval) }, - { "process_control_timeout", &fpm_conf_set_time, offsetof(struct fpm_global_config_s, process_control_timeout) }, - { "daemonize", &fpm_conf_set_boolean, offsetof(struct fpm_global_config_s, daemonize) }, - { "pid", &fpm_conf_set_string, offsetof(struct fpm_global_config_s, pid_file) }, - { "error_log", &fpm_conf_set_string, offsetof(struct fpm_global_config_s, error_log) }, + { "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 }, { 0, 0, 0 } }; static struct ini_value_parser_s ini_fpm_pool_options[] = { - { "user", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, user) }, - { "group", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, group) }, - { "chroot", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, chroot) }, - { "chdir", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, chdir) }, - { "request_terminate_timeout", &fpm_conf_set_time, offsetof(struct fpm_worker_pool_config_s, request_terminate_timeout) }, - { "request_slowlog_timeout", &fpm_conf_set_time, offsetof(struct fpm_worker_pool_config_s, request_slowlog_timeout) }, - { "slowlog", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, slowlog) }, - { "rlimit_files", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, rlimit_files) }, - { "rlimit_core", &fpm_conf_set_rlimit_core, offsetof(struct fpm_worker_pool_config_s, rlimit_core) }, - { "catch_workers_output", &fpm_conf_set_boolean, offsetof(struct fpm_worker_pool_config_s, catch_workers_output) }, - { "listen", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, listen_address) }, - { "listen.owner", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, listen_owner) }, - { "listen.group", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, listen_group) }, - { "listen.mode", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, listen_mode) }, - { "listen.backlog", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, listen_backlog) }, - { "listen.allowed_clients", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, listen_allowed_clients) }, - { "pm", &fpm_conf_set_pm, offsetof(struct fpm_worker_pool_config_s, pm) }, - { "pm.max_requests", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, pm_max_requests) }, - { "pm.max_children", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, pm_max_children) }, - { "pm.start_servers", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, pm_start_servers) }, - { "pm.min_spare_servers", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, pm_min_spare_servers) }, - { "pm.max_spare_servers", &fpm_conf_set_integer, offsetof(struct fpm_worker_pool_config_s, pm_max_spare_servers) }, - { "pm.status_path", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, pm_status_path) }, - { "ping.path", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, ping_path) }, - { "ping.response", &fpm_conf_set_string, offsetof(struct fpm_worker_pool_config_s, ping_response) }, + { "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.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.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) }, { 0, 0, 0 } }; @@ -111,11 +115,34 @@ static int fpm_conf_is_dir(char *path) /* {{{ */ } /* }}} */ +static int fpm_conf_expand_pool_name(char **value) { + char *token; + + if (!value || !*value) { + return 0; + } + + while ((token = strstr(*value, "$pool"))) { + char *buf; + char *p1 = *value; + char *p2 = token + strlen("$pool"); + if (!current_wp || !current_wp->config || !current_wp->config->name) { + return -1; + } + token[0] = '\0'; + spprintf(&buf, 0, "%s%s%s", p1, current_wp->config->name, p2); + *value = strdup(buf); + efree(buf); + } + + return 0; +} + static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); - long value_y = !strcasecmp(val, "yes") || !strcmp(val, "1") || !strcasecmp(val, "on") || !strcasecmp(val, "true"); - long value_n = !strcasecmp(val, "no") || !strcmp(val, "0") || !strcasecmp(val, "off") || !strcasecmp(val, "false"); + long value_y = !strcasecmp(val, "1"); + long value_n = !strcasecmp(val, ""); if (!value_y && !value_n) { return "invalid boolean value"; @@ -138,6 +165,9 @@ static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset) /* if (!new) { return "fpm_conf_set_string(): strdup() failed"; } + if (fpm_conf_expand_pool_name(&new) == -1) { + return "Can't use '$pool' when the pool is not defined"; + } *old = new; return NULL; @@ -146,17 +176,17 @@ static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset) /* static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset) /* {{{ */ { - int i; char *val = Z_STRVAL_P(value); + char *p; - for (i=0; i<strlen(val); i++) { - if ( i == 0 && val[i] == '-' ) continue; - if (val[i] < '0' || val[i] > '9') { - return("is not a valid number (greater or equal than zero"); + 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)"; } } * (int *) ((char *) *config + offset) = atoi(val); - return(NULL); + return NULL; } /* }}} */ @@ -204,7 +234,7 @@ static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset) { char *val = Z_STRVAL_P(value); - if (!strcmp(val, "debug")) { + if (!strcasecmp(val, "debug")) { fpm_globals.log_level = ZLOG_DEBUG; } else if (!strcasecmp(val, "notice")) { fpm_globals.log_level = ZLOG_NOTICE; @@ -227,7 +257,7 @@ static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offse char *val = Z_STRVAL_P(value); struct fpm_worker_pool_config_s *c = *config; - if (!strcmp(val, "unlimited")) { + if (!strcasecmp(val, "unlimited")) { c->rlimit_core = -1; } else { int int_value; @@ -255,9 +285,9 @@ static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset) /* {{{ { char *val = Z_STRVAL_P(value); struct fpm_worker_pool_config_s *c = *config; - if (!strcmp(val, "static")) { + if (!strcasecmp(val, "static")) { c->pm = PM_STYLE_STATIC; - } else if (!strcmp(val, "dynamic")) { + } else if (!strcasecmp(val, "dynamic")) { c->pm = PM_STYLE_DYNAMIC; } else { return "invalid process manager (static or dynamic)"; @@ -288,10 +318,13 @@ 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); + if (err) return err; kv->value = strdup(b ? "On" : "Off"); } else { kv->value = strdup(Z_STRVAL_P(value)); + if (fpm_conf_expand_pool_name(&kv->value) == -1) { + return "Can't use '$pool' when the pool is not defined"; + } } if (!kv->value) { @@ -322,7 +355,7 @@ static void *fpm_worker_pool_config_alloc() /* {{{ */ } memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s)); - wp->config->listen_backlog = -1; + wp->config->listen_backlog = FPM_BACKLOG_DEFAULT; if (!fpm_worker_all_pools) { fpm_worker_all_pools = wp; @@ -378,27 +411,68 @@ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */ free(wpc->chroot); free(wpc->chdir); free(wpc->slowlog); + free(wpc->prefix); return 0; } /* }}} */ -static int fpm_evaluate_full_path(char **path) /* {{{ */ +static int fpm_evaluate_full_path(char **path, struct fpm_worker_pool_s *wp, char *default_prefix, int expand) /* {{{ */ { - if (**path != '/') { - char *full_path; + char *prefix = NULL; + char *full_path; - full_path = malloc(sizeof(PHP_PREFIX) + strlen(*path) + 1); + if (!path || !*path || **path == '/') { + return 0; + } - if (!full_path) { - return -1; + if (wp && wp->config) { + prefix = wp->config->prefix; + } + + /* if the wp prefix is not set */ + if (prefix == NULL) { + prefix = fpm_globals.prefix; + } + + /* if the global prefix is not set */ + if (prefix == NULL) { + prefix = default_prefix ? default_prefix : PHP_PREFIX; + } + + if (expand) { + char *tmp; + tmp = strstr(*path, "$prefix"); + if (tmp != NULL) { + + if (tmp != *path) { + zlog(ZLOG_ERROR, "'$prefix' must be use at the begining of the value"); + return -1; + } + + if (strlen(*path) > strlen("$prefix")) { + free(*path); + tmp = strdup((*path) + strlen("$prefix")); + *path = tmp; + } else { + free(*path); + *path = NULL; + } } + } - sprintf(full_path, "%s/%s", PHP_PREFIX, *path); + if (*path) { + spprintf(&full_path, 0, "%s/%s", prefix, *path); free(*path); - *path = full_path; + *path = strdup(full_path); + efree(full_path); + } else { + *path = strdup(prefix); } + if (**path != '/' && wp != NULL && wp->config) { + return fpm_evaluate_full_path(path, NULL, default_prefix, expand); + } return 0; } /* }}} */ @@ -408,35 +482,44 @@ static int fpm_conf_process_all_pools() /* {{{ */ struct fpm_worker_pool_s *wp; if (!fpm_worker_all_pools) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "at least one pool section must be specified in config file"); + zlog(ZLOG_ERROR, "at least one pool section must be specified in config file"); return -1; } for (wp = fpm_worker_all_pools; wp; wp = wp->next) { + if (wp->config->prefix && *wp->config->prefix) { + fpm_evaluate_full_path(&wp->config->prefix, NULL, NULL, 0); + + if (!fpm_conf_is_dir(wp->config->prefix)) { + zlog(ZLOG_ERROR, "[pool %s] the prefix '%s' does not exist or is not a directory", wp->config->name, wp->config->prefix); + return -1; + } + } + if (wp->config->listen_address && *wp->config->listen_address) { wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address); if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') { - fpm_evaluate_full_path(&wp->config->listen_address); + fpm_evaluate_full_path(&wp->config->listen_address, wp, NULL, 0); } } else { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] no listen address have been defined!", wp->config->name); + zlog(ZLOG_ALERT, "[pool %s] no listen address have been defined!", wp->config->name); return -1; } if (!wp->config->user) { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] user has not been defined", wp->config->name); + 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_STUFF, ZLOG_ALERT, "[pool %s] the process manager is missing (static or dynamic)", wp->config->name); + zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static or dynamic)", wp->config->name); return -1; } if (wp->config->pm_max_children < 1) { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] pm.max_children must be a positive value", wp->config->name); + zlog(ZLOG_ALERT, "[pool %s] pm.max_children must be a positive value", wp->config->name); return -1; } @@ -444,66 +527,65 @@ static int fpm_conf_process_all_pools() /* {{{ */ struct fpm_worker_pool_config_s *config = wp->config; if (config->pm_min_spare_servers <= 0) { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) must be a positive value", wp->config->name, config->pm_min_spare_servers); + zlog(ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) must be a positive value", wp->config->name, config->pm_min_spare_servers); return -1; } if (config->pm_max_spare_servers <= 0) { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must be a positive value", wp->config->name, config->pm_max_spare_servers); + zlog(ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must be a positive value", wp->config->name, config->pm_max_spare_servers); return -1; } if (config->pm_min_spare_servers > config->pm_max_children || config->pm_max_spare_servers > config->pm_max_children) { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) and pm.max_spare_servers(%d) cannot be greater than pm.max_children(%d)", + 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; } if (config->pm_max_spare_servers < config->pm_min_spare_servers) { - zlog(ZLOG_STUFF, ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must not be less than pm.min_spare_servers(%d)", wp->config->name, config->pm_max_spare_servers, config->pm_min_spare_servers); + zlog(ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must not be less than pm.min_spare_servers(%d)", wp->config->name, config->pm_max_spare_servers, config->pm_min_spare_servers); return -1; } 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_STUFF, ZLOG_WARNING, "[pool %s] pm.start_servers is not set. It's been set to %d.", wp->config->name, config->pm_start_servers); + 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_STUFF, 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); + 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; } } + if (wp->config->slowlog && *wp->config->slowlog) { + fpm_evaluate_full_path(&wp->config->slowlog, wp, NULL, 0); + } if (wp->config->request_slowlog_timeout) { #if HAVE_FPM_TRACE if (! (wp->config->slowlog && *wp->config->slowlog)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] 'slowlog' must be specified for use with 'request_slowlog_timeout'", wp->config->name); + 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 (!warned) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'request_slowlog_timeout' is not supported on your system", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'request_slowlog_timeout' is not supported on your system", wp->config->name); warned = 1; } wp->config->request_slowlog_timeout = 0; #endif - } - if (wp->config->request_slowlog_timeout && wp->config->slowlog && *wp->config->slowlog) { - int fd; + if (wp->config->slowlog && *wp->config->slowlog) { + int fd; - fpm_evaluate_full_path(&wp->config->slowlog); - - if (wp->config->request_slowlog_timeout) { fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (0 > fd) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog); + zlog(ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog); return -1; } close(fd); @@ -515,18 +597,18 @@ static int fpm_conf_process_all_pools() /* {{{ */ int i; if (*ping != '/') { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the ping path '%s' must start with a '/'", wp->config->name, ping); + zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must start with a '/'", wp->config->name, ping); return -1; } if (strlen(ping) < 2) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the ping path '%s' is not long enough", wp->config->name, ping); + zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' is not long enough", wp->config->name, ping); return -1; } for (i=0; i<strlen(ping); i++) { if (!isalnum(ping[i]) && ping[i] != '/' && ping[i] != '-' && ping[i] != '_' && ping[i] != '.') { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the ping path '%s' must containt only the following characters '[alphanum]/_-.'", wp->config->name, ping); + zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must containt only the following characters '[alphanum]/_-.'", wp->config->name, ping); return -1; } } @@ -535,7 +617,7 @@ static int fpm_conf_process_all_pools() /* {{{ */ wp->config->ping_response = strdup("pong"); } else { if (strlen(wp->config->ping_response) < 1) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the ping response page '%s' is not long enough", wp->config->name, wp->config->ping_response); + zlog(ZLOG_ERROR, "[pool %s] the ping response page '%s' is not long enough", wp->config->name, wp->config->ping_response); return -1; } } @@ -552,73 +634,95 @@ static int fpm_conf_process_all_pools() /* {{{ */ /* struct fpm_status_s fpm_status; */ if (*status != '/') { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the status path '%s' must start with a '/'", wp->config->name, status); + zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must start with a '/'", wp->config->name, status); return -1; } if (strlen(status) < 2) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the status path '%s' is not long enough", wp->config->name, status); + 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_STUFF, ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.'", wp->config->name, status); + zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.'", wp->config->name, status); return -1; } } wp->shm_status = fpm_shm_alloc(sizeof(struct fpm_status_s)); if (!wp->shm_status) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] unable to allocate shared memory for status page '%s'", wp->config->name, status); + zlog(ZLOG_ERROR, "[pool %s] unable to allocate shared memory for status page '%s'", wp->config->name, status); return -1; } fpm_status_update_accepted_conn(wp->shm_status, 0); - fpm_status_update_activity(wp->shm_status, -1, -1, -1, 1); + fpm_status_update_activity(wp->shm_status, -1, -1, -1, 0, -1, 1); + fpm_status_update_max_children_reached(wp->shm_status, 0); fpm_status_set_pm(wp->shm_status, wp->config->pm); /* memset(&fpm_status.last_update, 0, sizeof(fpm_status.last_update)); */ } if (wp->config->chroot && *wp->config->chroot) { + + fpm_evaluate_full_path(&wp->config->chroot, wp, NULL, 1); + if (*wp->config->chroot != '/') { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the chroot path '%s' must start with a '/'", wp->config->name, wp->config->chroot); + 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_STUFF, ZLOG_ERROR, "[pool %s] the chroot path '%s' does not exist or is not a directory", wp->config->name, 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; } } if (wp->config->chdir && *wp->config->chdir) { + + fpm_evaluate_full_path(&wp->config->chdir, wp, NULL, 0); + if (*wp->config->chdir != '/') { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the chdir path '%s' must start with a '/'", wp->config->name, wp->config->chdir); + zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' must start with a '/'", wp->config->name, wp->config->chdir); return -1; } if (wp->config->chroot) { char *buf; - size_t len; - len = strlen(wp->config->chroot) + strlen(wp->config->chdir) + 1; - buf = malloc(sizeof(char) * len); - if (!buf) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "[pool %s] malloc() failed", wp->config->name); - return -1; - } - snprintf(buf, len, "%s%s", wp->config->chroot, wp->config->chdir); + spprintf(&buf, 0, "%s/%s", wp->config->chroot, wp->config->chdir); + if (!fpm_conf_is_dir(buf)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the chdir path '%s' within the chroot path '%s' ('%s') does not exist or is not a directory", wp->config->name, wp->config->chdir, wp->config->chroot, buf); - free(buf); + zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' within the chroot path '%s' ('%s') does not exist or is not a directory", wp->config->name, wp->config->chdir, wp->config->chroot, buf); + efree(buf); return -1; } - free(buf); + + efree(buf); } else { if (!fpm_conf_is_dir(wp->config->chdir)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] the chdir path '%s' does not exist or is not a directory", wp->config->name, wp->config->chdir); + zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' does not exist or is not a directory", wp->config->name, wp->config->chdir); return -1; } } } + if (!wp->config->chroot) { + struct key_value_s *kv; + char *options[] = FPM_PHP_INI_TO_EXPAND; + char **p; + + for (kv = wp->config->php_values; kv; kv = kv->next) { + for (p=options; *p; p++) { + if (!strcasecmp(kv->key, *p)) { + fpm_evaluate_full_path(&kv->value, wp, NULL, 0); + } + } + } + for (kv = wp->config->php_admin_values; kv; kv = kv->next) { + for (p=options; *p; p++) { + if (!strcasecmp(kv->key, *p)) { + fpm_evaluate_full_path(&kv->value, wp, NULL, 0); + } + } + } + } } return 0; } @@ -628,7 +732,7 @@ int fpm_conf_unlink_pid() /* {{{ */ { if (fpm_global_config.pid_file) { if (0 > unlink(fpm_global_config.pid_file)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file); + zlog(ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file); return -1; } } @@ -648,14 +752,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_STUFF, ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file); + zlog(ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file); return -1; } len = sprintf(buf, "%d", (int) fpm_globals.parent_pid); if (len != write(fd, buf, len)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "write() failed"); + zlog(ZLOG_SYSERROR, "write() failed"); return -1; } close(fd); @@ -667,18 +771,14 @@ int fpm_conf_write_pid() /* {{{ */ static int fpm_conf_post_process() /* {{{ */ { if (fpm_global_config.pid_file) { - fpm_evaluate_full_path(&fpm_global_config.pid_file); + fpm_evaluate_full_path(&fpm_global_config.pid_file, NULL, PHP_LOCALSTATEDIR, 0); } if (!fpm_global_config.error_log) { - char *tmp_log_path; - - spprintf(&tmp_log_path, 0, "%s/log/php-fpm.log", PHP_LOCALSTATEDIR); - fpm_global_config.error_log = strdup(tmp_log_path); - efree(tmp_log_path); + fpm_global_config.error_log = strdup("log/php-fpm.log"); } - fpm_evaluate_full_path(&fpm_global_config.error_log); + fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0); if (0 > fpm_stdio_open_error_log(0)) { return -1; @@ -694,6 +794,7 @@ static void fpm_conf_cleanup(int which, void *arg) /* {{{ */ free(fpm_global_config.error_log); fpm_global_config.pid_file = 0; fpm_global_config.error_log = 0; + free(fpm_globals.config); } /* }}} */ @@ -714,12 +815,14 @@ static void fpm_conf_ini_parser_include(char *inc, void *arg TSRMLS_DC) /* {{{ * if ((i = glob(inc, GLOB_ERR | GLOB_MARK | GLOB_NOSORT, NULL, &g)) != 0) { #ifdef GLOB_NOMATCH if (i == GLOB_NOMATCH) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "Nothing matches the include pattern '%s' from %s at line %d.", inc, filename, ini_lineno); + zlog(ZLOG_WARNING, "Nothing matches the include pattern '%s' from %s at line %d.", inc, filename, ini_lineno); + efree(filename); return; } #endif /* GLOB_NOMATCH */ - zlog(ZLOG_STUFF, ZLOG_ERROR, "Unable to globalize '%s' (ret=%d) from %s at line %d.", inc, i, filename, ini_lineno); + zlog(ZLOG_ERROR, "Unable to globalize '%s' (ret=%d) from %s at line %d.", inc, i, filename, ini_lineno); *error = 1; + efree(filename); return; } @@ -728,8 +831,9 @@ static void fpm_conf_ini_parser_include(char *inc, void *arg TSRMLS_DC) /* {{{ * if (len < 1) continue; if (g.gl_pathv[i][len - 1] == '/') continue; /* don't parse directories */ if (0 > fpm_conf_load_ini_file(g.gl_pathv[i] TSRMLS_CC)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "Unable to include %s from %s at line %d", g.gl_pathv[i], filename, ini_lineno); + zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", g.gl_pathv[i], filename, ini_lineno); *error = 1; + efree(filename); return; } } @@ -737,11 +841,14 @@ static void fpm_conf_ini_parser_include(char *inc, void *arg TSRMLS_DC) /* {{{ * } #else /* HAVE_GLOB */ if (0 > fpm_conf_load_ini_file(inc TSRMLS_CC)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "Unable to include %s from %s at line %d", inc, filename, ini_lineno); + zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", inc, filename, ini_lineno); *error = 1; + efree(filename); return; } #endif /* HAVE_GLOB */ + + efree(filename); } /* }}} */ @@ -770,13 +877,13 @@ static void fpm_conf_ini_parser_section(zval *section, void *arg TSRMLS_DC) /* { /* it's a new pool */ config = (struct fpm_worker_pool_config_s *)fpm_worker_pool_config_alloc(); if (!current_wp || !config) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] Unable to alloc a new WorkerPool for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section)); + zlog(ZLOG_ERROR, "[%s:%d] Unable to alloc a new WorkerPool for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section)); *error = 1; return; } config->name = strdup(Z_STRVAL_P(section)); if (!config->name) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] Unable to alloc memory for configuration name for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section)); + zlog(ZLOG_ERROR, "[%s:%d] Unable to alloc memory for configuration name for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section)); *error = 1; return; } @@ -790,14 +897,14 @@ static void fpm_conf_ini_parser_entry(zval *name, zval *value, void *arg TSRMLS_ int *error = (int *)arg; if (!value) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] value is NULL for a ZEND_INI_PARSER_ENTRY", ini_filename, ini_lineno); + zlog(ZLOG_ERROR, "[%s:%d] value is NULL for a ZEND_INI_PARSER_ENTRY", ini_filename, ini_lineno); *error = 1; return; } if (!strcmp(Z_STRVAL_P(name), "include")) { if (ini_include) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] two includes at the same time !", ini_filename, ini_lineno); + zlog(ZLOG_ERROR, "[%s:%d] two includes at the same time !", ini_filename, ini_lineno); *error = 1; return; } @@ -817,14 +924,14 @@ static void fpm_conf_ini_parser_entry(zval *name, zval *value, void *arg TSRMLS_ if (!strcasecmp(parser->name, Z_STRVAL_P(name))) { char *ret; if (!parser->parser) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] the parser for entry '%s' is not defined", ini_filename, ini_lineno, parser->name); + zlog(ZLOG_ERROR, "[%s:%d] the parser for entry '%s' is not defined", ini_filename, ini_lineno, parser->name); *error = 1; return; } ret = parser->parser(value, &config, parser->offset); if (ret) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] unable to parse value for entry '%s': %s", ini_filename, ini_lineno, parser->name, ret); + zlog(ZLOG_ERROR, "[%s:%d] unable to parse value for entry '%s': %s", ini_filename, ini_lineno, parser->name, ret); *error = 1; return; } @@ -835,7 +942,7 @@ static void fpm_conf_ini_parser_entry(zval *name, zval *value, void *arg TSRMLS_ } /* nothing has been found if we got here */ - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] unknown entry '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name)); + zlog(ZLOG_ERROR, "[%s:%d] unknown entry '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name)); *error = 1; } /* }}} */ @@ -846,45 +953,60 @@ static void fpm_conf_ini_parser_array(zval *name, zval *key, zval *value, void * char *err = NULL; void *config; - if (!Z_STRVAL_P(key) || !Z_STRVAL_P(value) || !*Z_STRVAL_P(key) || !*Z_STRVAL_P(value)) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] Mispell array ?", ini_filename, ini_lineno); + if (!Z_STRVAL_P(key) || !Z_STRVAL_P(value) || !*Z_STRVAL_P(key)) { + zlog(ZLOG_ERROR, "[%s:%d] Misspelled array ?", ini_filename, ini_lineno); *error = 1; return; } if (!current_wp || !current_wp->config) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] Array are not allowed in the global section", ini_filename, ini_lineno); + zlog(ZLOG_ERROR, "[%s:%d] Array are not allowed in the global section", ini_filename, ini_lineno); *error = 1; return; } if (!strcmp("env", Z_STRVAL_P(name))) { - config = (char *)current_wp->config + offsetof(struct fpm_worker_pool_config_s, env); + 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(env); err = fpm_conf_set_array(key, value, &config, 0); } else if (!strcmp("php_value", Z_STRVAL_P(name))) { - config = (char *)current_wp->config + offsetof(struct fpm_worker_pool_config_s, php_values); + 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))) { - config = (char *)current_wp->config + offsetof(struct fpm_worker_pool_config_s, php_admin_values); + 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); } else if (!strcmp("php_flag", Z_STRVAL_P(name))) { - config = (char *)current_wp->config + offsetof(struct fpm_worker_pool_config_s, php_values); + config = (char *)current_wp->config + WPO(php_values); err = fpm_conf_set_array(key, value, &config, 1); } else if (!strcmp("php_admin_flag", Z_STRVAL_P(name))) { - config = (char *)current_wp->config + offsetof(struct fpm_worker_pool_config_s, php_admin_values); + config = (char *)current_wp->config + WPO(php_admin_values); err = fpm_conf_set_array(key, value, &config, 1); } else { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] unknown directive '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name)); + zlog(ZLOG_ERROR, "[%s:%d] unknown directive '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name)); *error = 1; return; } if (err) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] error while parsing '%s[%s]' : %s", ini_filename, ini_lineno, Z_STRVAL_P(name), Z_STRVAL_P(key), err); + zlog(ZLOG_ERROR, "[%s:%d] error while parsing '%s[%s]' : %s", ini_filename, ini_lineno, Z_STRVAL_P(name), Z_STRVAL_P(key), err); *error = 1; return; } @@ -910,7 +1032,7 @@ static void fpm_conf_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback fpm_conf_ini_parser_array(arg1, arg3, arg2, error TSRMLS_CC); break;; default: - zlog(ZLOG_STUFF, ZLOG_ERROR, "[%s:%d] Unknown INI syntax", ini_filename, ini_lineno); + zlog(ZLOG_ERROR, "[%s:%d] Unknown INI syntax", ini_filename, ini_lineno); *error = 1; break;; } @@ -928,18 +1050,18 @@ int fpm_conf_load_ini_file(char *filename TSRMLS_DC) /* {{{ */ int ret = 1; if (!filename || !filename[0]) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "Configuration file is empty"); + zlog(ZLOG_ERROR, "Configuration file is empty"); return -1; } fd = open(filename, O_RDONLY, 0); if (fd < 0) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "Unable to open file '%s', errno=%d", filename, errno); + zlog(ZLOG_ERROR, "Unable to open file '%s', errno=%d", filename, errno); return -1; } if (ini_recursion++ > 4) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "You can include more than 5 files recusively"); + zlog(ZLOG_ERROR, "You can include more than 5 files recusively"); return -1; } @@ -953,7 +1075,7 @@ int fpm_conf_load_ini_file(char *filename TSRMLS_DC) /* {{{ */ buf[n++] = '\n'; ini_lineno++; ini_filename = filename; - tmp = zend_parse_ini_string(buf, 1, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t)fpm_conf_ini_parser, &error TSRMLS_CC); + tmp = zend_parse_ini_string(buf, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fpm_conf_ini_parser, &error TSRMLS_CC); ini_filename = filename; if (error || tmp == FAILURE) { if (ini_include) free(ini_include); @@ -964,7 +1086,7 @@ int fpm_conf_load_ini_file(char *filename TSRMLS_DC) /* {{{ */ if (ini_include) { char *tmp = ini_include; ini_include = NULL; - fpm_evaluate_full_path(&tmp); + fpm_evaluate_full_path(&tmp, NULL, NULL, 0); fpm_conf_ini_parser_include(tmp, &error TSRMLS_CC); if (error) { free(tmp); @@ -983,30 +1105,119 @@ int fpm_conf_load_ini_file(char *filename TSRMLS_DC) /* {{{ */ } /* }}} */ -int fpm_conf_init_main() /* {{{ */ +static void fpm_conf_dump() /* {{{ */ +{ + struct fpm_worker_pool_s *wp; + + 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)); + zlog(ZLOG_NOTICE, "\tlog_level = %s", zlog_get_level_name()); + 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, " "); + + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { + struct key_value_s *kv; + if (!wp->config) continue; + zlog(ZLOG_NOTICE, "[%s]", STR2STR(wp->config->name)); + 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)); + zlog(ZLOG_NOTICE, "\tlisten.group = %s", STR2STR(wp->config->listen_group)); + zlog(ZLOG_NOTICE, "\tlisten.mode = %s", STR2STR(wp->config->listen_mode)); + 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.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, "\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, "\trlimit_files = %d", wp->config->rlimit_files); + zlog(ZLOG_NOTICE, "\trlimit_core = %d", wp->config->rlimit_core); + + for (kv = wp->config->env; kv; kv = kv->next) { + zlog(ZLOG_NOTICE, "\tenv[%s] = %s", kv->key, kv->value); + } + + for (kv = wp->config->php_values; kv; kv = kv->next) { + zlog(ZLOG_NOTICE, "\tphp_value[%s] = %s", kv->key, kv->value); + } + + for (kv = wp->config->php_admin_values; kv; kv = kv->next) { + zlog(ZLOG_NOTICE, "\tphp_admin_value[%s] = %s", kv->key, kv->value); + } + zlog(ZLOG_NOTICE, " "); + } +} +/* }}} */ + +int fpm_conf_init_main(int test_conf) /* {{{ */ { - char *filename = fpm_globals.config; - int free = 0; int ret; TSRMLS_FETCH(); - if (filename == NULL) { - spprintf(&filename, 0, "%s/php-fpm.conf", PHP_SYSCONFDIR); - free = 1; + if (fpm_globals.prefix && *fpm_globals.prefix) { + if (!fpm_conf_is_dir(fpm_globals.prefix)) { + zlog(ZLOG_ERROR, "the global prefix '%s' does not exist or is not a directory", fpm_globals.prefix); + return -1; + } } - ret = fpm_conf_load_ini_file(filename TSRMLS_CC); + if (fpm_globals.config == NULL) { + char *tmp; + + if (fpm_globals.prefix == NULL) { + spprintf(&tmp, 0, "%s/php-fpm.conf", PHP_SYSCONFDIR); + } else { + spprintf(&tmp, 0, "%s/etc/php-fpm.conf", fpm_globals.prefix); + } + + if (!tmp) { + zlog(ZLOG_SYSERROR, "spprintf() failed (tmp for fpm_globals.config)"); + return -1; + } + + fpm_globals.config = strdup(tmp); + efree(tmp); + + if (!fpm_globals.config) { + zlog(ZLOG_SYSERROR, "spprintf() failed (fpm_globals.config)"); + return -1; + } + } + + ret = fpm_conf_load_ini_file(fpm_globals.config TSRMLS_CC); if (0 > ret) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "failed to load configuration file '%s'", filename); - if (free) efree(filename); + zlog(ZLOG_ERROR, "failed to load configuration file '%s'", fpm_globals.config); return -1; } - if (free) efree(filename); - if (0 > fpm_conf_post_process()) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "failed to post process the configuration"); + zlog(ZLOG_ERROR, "failed to post process the configuration"); + return -1; + } + + if (test_conf) { + if (test_conf > 1) { + fpm_conf_dump(); + } + zlog(ZLOG_NOTICE, "configuration file %s test is successful\n", fpm_globals.config); return -1; } diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h index aace7811e..ac38ee2e9 100644 --- a/sapi/fpm/fpm/fpm_conf.h +++ b/sapi/fpm/fpm/fpm_conf.h @@ -10,6 +10,10 @@ #define FPM_CONF_MAX_PONG_LENGTH 64 +#define STR2STR(a) (a ? a : "undefined") +#define BOOL2STR(a) (a ? "yes" : "no") +#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : "dynamic") + struct key_value_s; struct key_value_s { @@ -31,6 +35,7 @@ extern struct fpm_global_config_s fpm_global_config; struct fpm_worker_pool_config_s { char *name; + char *prefix; char *user; char *group; char *chroot; @@ -69,7 +74,7 @@ struct ini_value_parser_s { enum { PM_STYLE_STATIC = 1, PM_STYLE_DYNAMIC = 2 }; -int fpm_conf_init_main(); +int fpm_conf_init_main(int test_conf); int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc); int fpm_conf_write_pid(); int fpm_conf_unlink_pid(); diff --git a/sapi/fpm/fpm/fpm_config.h b/sapi/fpm/fpm/fpm_config.h index 165bd7d62..3637f376c 100644 --- a/sapi/fpm/fpm/fpm_config.h +++ b/sapi/fpm/fpm/fpm_config.h @@ -1,44 +1,83 @@ - - /* $Id: fpm_config.h,v 1.16 2008/05/25 00:30:43 anight Exp $ */ - /* (c) 2007,2008 Andrei Nigmatulin */ +/* $Id: fpm_config.h,v 1.16 2008/05/25 00:30:43 anight Exp $ */ +/* (c) 2007,2008 Andrei Nigmatulin */ #include <php_config.h> + #ifdef FPM_AUTOCONFIG_H -#include <fpm_autoconfig.h> +# include <fpm_autoconfig.h> #endif /* Solaris does not have it */ #ifndef INADDR_NONE -#define INADDR_NONE (-1) +# define INADDR_NONE (-1) #endif /* If we're not using GNU C, elide __attribute__ */ #ifndef __GNUC__ -# define __attribute__(x) /*NOTHING*/ +# define __attribute__(x) /*NOTHING*/ #endif +/* Missing timer* macros (for solaris) */ +#ifndef timerisset +# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#endif + +#ifndef timerclear +# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) +#endif -/* Solaris does not have it */ #ifndef timersub -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ +# define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +#ifndef timeradd +# define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) \ + { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ } while (0) #endif +#ifndef timercmp +/* does not work for >= and <= */ +# define timercmp(a, b, CMP) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_usec CMP (b)->tv_usec) : \ + ((a)->tv_sec CMP (b)->tv_sec)) +#endif +/* endof timer* macros */ + #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) #endif #if defined(HAVE_PTRACE) || defined(PROC_MEM_FILE) || defined(HAVE_MACH_VM_READ) -#define HAVE_FPM_TRACE 1 +# define HAVE_FPM_TRACE 1 +#else +# define HAVE_FPM_TRACE 0 +#endif + +#if defined(HAVE_LQ_TCP_INFO) || defined(HAVE_LQ_SO_LISTENQ) +# define HAVE_FPM_LQ 1 #else -#define HAVE_FPM_TRACE 0 +# define HAVE_FPM_LQ 0 #endif diff --git a/sapi/fpm/fpm/fpm_env.c b/sapi/fpm/fpm/fpm_env.c index ddc4705ec..aa647d15b 100644 --- a/sapi/fpm/fpm/fpm_env.c +++ b/sapi/fpm/fpm/fpm_env.c @@ -12,8 +12,16 @@ #include <string.h> #include "fpm_env.h" +#include "fpm.h" #include "zlog.h" +#ifndef HAVE_SETPROCTITLE +#ifdef __linux__ +static char **fpm_env_argv = NULL; +static size_t fpm_env_argv_len = 0; +#endif +#endif + #ifndef HAVE_SETENV # ifdef (__sparc__ || __sparc) int setenv(char *name, char *value, int clobber) /* {{{ */ @@ -111,9 +119,30 @@ static char * nvmatch(char *s1, char *s2) /* {{{ */ /* }}} */ #endif +void fpm_env_setproctitle(char *title) /* {{{ */ +{ +#ifdef HAVE_SETPROCTITLE + setproctitle("%s", title); +#else +#ifdef __linux__ + if (fpm_env_argv != NULL && fpm_env_argv_len > strlen(SETPROCTITLE_PREFIX) + 3) { + memset(fpm_env_argv[0], 0, fpm_env_argv_len); + strncpy(fpm_env_argv[0], SETPROCTITLE_PREFIX, fpm_env_argv_len - 2); + strncpy(fpm_env_argv[0] + strlen(SETPROCTITLE_PREFIX), title, fpm_env_argv_len - strlen(SETPROCTITLE_PREFIX) - 2); + fpm_env_argv[1] = NULL; + } +#endif +#endif +} +/* }}} */ + int fpm_env_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ { struct key_value_s *kv; + char *title; + spprintf(&title, 0, "pool %s", wp->config->name); + fpm_env_setproctitle(title); + efree(title); clearenv(); @@ -169,12 +198,79 @@ static int fpm_env_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ int fpm_env_init_main() /* {{{ */ { struct fpm_worker_pool_s *wp; + int i; + char *first = NULL; + char *last = NULL; + char *title; for (wp = fpm_worker_all_pools; wp; wp = wp->next) { if (0 > fpm_env_conf_wp(wp)) { return -1; } } +#ifndef HAVE_SETPROCTITLE +#ifdef __linux__ + /* + * This piece of code has been inspirated from nginx and pureftpd code, whic + * are under BSD licence. + * + * To change the process title in Linux we have to set argv[1] to NULL + * and to copy the title to the same place where the argv[0] points to. + * However, argv[0] may be too small to hold a new title. Fortunately, Linux + * store argv[] and environ[] one after another. So we should ensure that is + * the continuous memory and then we allocate the new memory for environ[] + * and copy it. After this we could use the memory starting from argv[0] for + * our process title. + */ + + for (i = 0; i < fpm_globals.argc; i++) { + if (first == NULL) { + first = fpm_globals.argv[i]; + } + if (last == NULL || fpm_globals.argv[i] == last + 1) { + last = fpm_globals.argv[i] + strlen(fpm_globals.argv[i]); + } + } + if (environ) { + for (i = 0; environ[i]; i++) { + if (first == NULL) { + first = environ[i]; + } + if (last == NULL || environ[i] == last + 1) { + last = environ[i] + strlen(environ[i]); + } + } + } + if (first == NULL || last == NULL) { + return 0; + } + + fpm_env_argv_len = last - first; + fpm_env_argv = fpm_globals.argv; + if (environ != NULL) { + char **new_environ; + unsigned int env_nb = 0U; + + while (environ[env_nb]) { + env_nb++; + } + + if ((new_environ = malloc((1U + env_nb) * sizeof (char *))) == NULL) { + return -1; + } + new_environ[env_nb] = NULL; + while (env_nb > 0U) { + env_nb--; + new_environ[env_nb] = strdup(environ[env_nb]); + } + environ = new_environ; + } +#endif +#endif + + spprintf(&title, 0, "master process (%s)", fpm_globals.config); + fpm_env_setproctitle(title); + efree(title); return 0; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_env.h b/sapi/fpm/fpm/fpm_env.h index 0f79ed786..bf472368d 100644 --- a/sapi/fpm/fpm/fpm_env.h +++ b/sapi/fpm/fpm/fpm_env.h @@ -7,8 +7,11 @@ #include "fpm_worker_pool.h" +#define SETPROCTITLE_PREFIX "php-fpm: " + int fpm_env_init_child(struct fpm_worker_pool_s *wp); int fpm_env_init_main(); +void fpm_env_setproctitle(char *title); extern char **environ; diff --git a/sapi/fpm/fpm/fpm_events.c b/sapi/fpm/fpm/fpm_events.c index aa4086d9d..66ff393e2 100644 --- a/sapi/fpm/fpm/fpm_events.c +++ b/sapi/fpm/fpm/fpm_events.c @@ -9,6 +9,9 @@ #include <stdlib.h> /* for putenv */ #include <string.h> +#include <php.h> +#include <php_network.h> + #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 { @@ -38,43 +65,43 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */ if (res <= 0) { if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed"); + zlog(ZLOG_SYSERROR, "read() failed"); } return; } switch (c) { case 'C' : /* SIGCHLD */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "received SIGCHLD"); - fpm_children_bury(base); + zlog(ZLOG_DEBUG, "received SIGCHLD"); + fpm_children_bury(); break; case 'I' : /* SIGINT */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "received SIGINT"); - zlog(ZLOG_STUFF, ZLOG_NOTICE, "Terminating ..."); - fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET, base); + zlog(ZLOG_DEBUG, "received SIGINT"); + zlog(ZLOG_NOTICE, "Terminating ..."); + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET); break; case 'T' : /* SIGTERM */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "received SIGTERM"); - zlog(ZLOG_STUFF, ZLOG_NOTICE, "Terminating ..."); - fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET, base); + zlog(ZLOG_DEBUG, "received SIGTERM"); + zlog(ZLOG_NOTICE, "Terminating ..."); + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET); break; case 'Q' : /* SIGQUIT */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "received SIGQUIT"); - zlog(ZLOG_STUFF, ZLOG_NOTICE, "Finishing ..."); - fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET, base); + zlog(ZLOG_DEBUG, "received SIGQUIT"); + zlog(ZLOG_NOTICE, "Finishing ..."); + fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET); break; case '1' : /* SIGUSR1 */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "received SIGUSR1"); + zlog(ZLOG_DEBUG, "received SIGUSR1"); if (0 == fpm_stdio_open_error_log(1)) { - zlog(ZLOG_STUFF, ZLOG_NOTICE, "log file re-opened"); + zlog(ZLOG_NOTICE, "log file re-opened"); } else { - zlog(ZLOG_STUFF, ZLOG_ERROR, "unable to re-opened log file"); + zlog(ZLOG_ERROR, "unable to re-opened log file"); } break; case '2' : /* SIGUSR2 */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "received SIGUSR2"); - zlog(ZLOG_STUFF, ZLOG_NOTICE, "Reloading in progress ..."); - fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET, base); + zlog(ZLOG_DEBUG, "received SIGUSR2"); + zlog(ZLOG_NOTICE, "Reloading in progress ..."); + 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) /* {{{ */ { - *base = event_base_new(); + struct fpm_event_queue_s *elt; - zlog(ZLOG_STUFF, ZLOG_DEBUG, "libevent: using %s", event_base_get_method(*base)); + if (!queue || !ev) { + return -1; + } - if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, *base)) { + 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; } - return 0; + 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_loop(struct event_base *base) /* {{{ */ +int fpm_event_init_main() /* {{{ */ { - static struct event signal_fd_event; - - 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_STUFF, ZLOG_NOTICE, "ready to handle connections"); - event_base_dispatch(base); + 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); + } + } + + /* 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; + } + + 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_add(int fd, struct event_base *base, struct event *ev, void (*callback)(int, short, void *), void *arg) /* {{{ */ +void fpm_event_loop() /* {{{ */ +{ + 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); + + zlog(ZLOG_NOTICE, "ready to handle connections"); + + 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; + } + } +} +/* }}} */ + +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 7a5a9a53b..bec13ba5e 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 2ee4539b2..8f0d76007 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -152,6 +152,8 @@ static const opt_struct OPTIONS[] = { {'?', 0, "usage"},/* help alias (both '?' and 'usage') */ {'v', 0, "version"}, {'y', 1, "fpm-config"}, + {'t', 0, "test"}, + {'p', 1, "prefix"}, {'-', 0, NULL} /* end of args */ }; @@ -166,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 @@ -959,7 +960,7 @@ static void php_cgi_usage(char *argv0) prog = "php"; } - php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-c <file>] [-d foo[=bar]] [-y <file>]\n" + php_printf( "Usage: %s [-n] [-e] [-h] [-i] [-m] [-v] [-t] [-p <prefix> ] [-c <file>] [-d foo[=bar]] [-y <file>]\n" " -c <path>|<file> Look for php.ini file in this directory\n" " -n No php.ini file will be used\n" " -d foo[=bar] Define INI entry foo with value 'bar'\n" @@ -968,9 +969,12 @@ static void php_cgi_usage(char *argv0) " -i PHP information\n" " -m Show compiled in modules\n" " -v Version number\n" + " -p, --prefix <dir>\n" + " Specify alternative prefix path to FastCGI process manager (default: %s).\n" " -y, --fpm-config <file>\n" - " Specify alternative path to FastCGI process manager config file.\n", - prog); + " Specify alternative path to FastCGI process manager config file.\n" + " -t, --test Test FPM configuration and exit\n", + prog, PHP_PREFIX); } /* }}} */ @@ -1372,7 +1376,7 @@ static void init_request_info(TSRMLS_D) int mode = ZEND_INI_USER; char *tmp; spprintf(&tmp, 0, "%s\n", ini); - zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode TSRMLS_CC); + zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode TSRMLS_CC); efree(tmp); } @@ -1381,7 +1385,7 @@ static void init_request_info(TSRMLS_D) int mode = ZEND_INI_SYSTEM; char *tmp; spprintf(&tmp, 0, "%s\n", ini); - zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode TSRMLS_CC); + zend_parse_ini_string(tmp, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fastcgi_ini_parser, &mode TSRMLS_CC); efree(tmp); } } @@ -1406,7 +1410,7 @@ static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_ return; } - if (!value || strlen(value) < 1) { + if (!value) { fprintf(stderr, "Passing INI directive through FastCGI: empty value for key '%s'\n", key); return; } @@ -1480,7 +1484,6 @@ static PHP_MINFO_FUNCTION(cgi) { php_info_print_table_start(); php_info_print_table_row(2, "php-fpm", "active"); - php_info_print_table_row(2, "php-fpm version", PHP_FPM_VERSION); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); @@ -1548,6 +1551,8 @@ int main(int argc, char *argv[]) int fcgi_fd = 0; fcgi_request request; char *fpm_config = NULL; + char *fpm_prefix = NULL; + int test_conf = 0; fcgi_init(); @@ -1585,9 +1590,11 @@ int main(int argc, char *argv[]) } cgi_sapi_module.php_ini_path_override = strdup(php_optarg); break; + case 'n': cgi_sapi_module.php_ini_ignore = 1; break; + case 'd': { /* define ini entries on command line */ int len = strlen(php_optarg); @@ -1619,14 +1626,23 @@ int main(int argc, char *argv[]) } break; } + case 'y': fpm_config = php_optarg; break; + case 'p': + fpm_prefix = php_optarg; + break; + case 'e': /* enable extended info output */ CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; break; + case 't': + test_conf++; + break; + case 'm': /* list compiled in modules */ cgi_sapi_module.startup(&cgi_sapi_module); php_output_startup(); @@ -1763,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), &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); @@ -1920,8 +1936,10 @@ fastcgi_request_done: out: SG(server_context) = NULL; - php_module_shutdown(TSRMLS_C); - sapi_shutdown(); + if (parent) { + php_module_shutdown(TSRMLS_C); + sapi_shutdown(); + } #ifdef ZTS tsrm_shutdown(); diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index ce5dac4bc..eeba71301 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -139,6 +139,7 @@ static int fpm_php_set_allowed_clients(struct fpm_worker_pool_s *wp) /* {{{ */ } /* }}} */ +#if 0 /* Comment out this non used function. It could be used later. */ static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp) /* {{{ */ { char max_workers[10 + 1]; /* 4294967295 */ @@ -151,6 +152,7 @@ static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp) /* {{{ */ return 0; } /* }}} */ +#endif char *fpm_php_script_filename(TSRMLS_D) /* {{{ */ { diff --git a/sapi/fpm/fpm/fpm_php.h b/sapi/fpm/fpm/fpm_php.h index 8c4b58ceb..81e533267 100644 --- a/sapi/fpm/fpm/fpm_php.h +++ b/sapi/fpm/fpm/fpm_php.h @@ -11,6 +11,26 @@ #include "build-defs.h" /* for PHP_ defines */ #include "fpm/fpm_conf.h" +#define FPM_PHP_INI_TO_EXPAND \ + { \ + "error_log", \ + "extension_dir", \ + "mime_magic.magicfile", \ + "sendmail_path", \ + "session.cookie_path", \ + "session_pgsql.sem_file_name", \ + "soap.wsdl_cache_dir", \ + "uploadprogress.file.filename_template", \ + "xdebug.output_dir", \ + "xdebug.profiler_output_dir", \ + "xdebug.trace_output_dir", \ + "xmms.path", \ + "axis2.client_home", \ + "blenc.key_file", \ + "coin_acceptor.device", \ + NULL \ + } + struct fpm_worker_pool_s; int fpm_php_init_child(struct fpm_worker_pool_s *wp); diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c index 306a592c8..03874584f 100644 --- a/sapi/fpm/fpm/fpm_php_trace.c +++ b/sapi/fpm/fpm/fpm_php_trace.c @@ -139,12 +139,12 @@ void fpm_php_trace(struct fpm_child_s *child) /* {{{ */ TSRMLS_FETCH(); FILE *slowlog; - zlog(ZLOG_STUFF, ZLOG_NOTICE, "about to trace %d", (int) child->pid); + zlog(ZLOG_NOTICE, "about to trace %d", (int) child->pid); slowlog = fopen(child->wp->config->slowlog, "a+"); if (!slowlog) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fopen(%s) failed", child->wp->config->slowlog); + zlog(ZLOG_SYSERROR, "fopen(%s) failed", child->wp->config->slowlog); goto done0; } @@ -167,7 +167,7 @@ done0: fpm_pctl_kill(child->pid, FPM_PCTL_CONT); child->tracer = 0; - zlog(ZLOG_STUFF, ZLOG_NOTICE, "finished trace of %d", (int) child->pid); + zlog(ZLOG_NOTICE, "finished trace of %d", (int) child->pid); } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_process_ctl.c b/sapi/fpm/fpm/fpm_process_ctl.c index b24f950f5..badda1408 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.c +++ b/sapi/fpm/fpm/fpm_process_ctl.c @@ -19,6 +19,7 @@ #include "fpm_request.h" #include "fpm_worker_pool.h" #include "fpm_status.h" +#include "fpm_sockets.h" #include "zlog.h" @@ -48,36 +49,25 @@ 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; } /* }}} */ static void fpm_pctl_exit() /* {{{ */ { - zlog(ZLOG_STUFF, ZLOG_NOTICE, "exiting, bye-bye!"); + zlog(ZLOG_NOTICE, "exiting, bye-bye!"); fpm_conf_unlink_pid(); fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT_MAIN); @@ -90,7 +80,7 @@ static void fpm_pctl_exit() /* {{{ */ static void fpm_pctl_exec() /* {{{ */ { - zlog(ZLOG_STUFF, ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\"" + zlog(ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\"" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "})", @@ -109,7 +99,7 @@ static void fpm_pctl_exec() /* {{{ */ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC); execvp(saved_argv[0], saved_argv); - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "execvp() failed"); + zlog(ZLOG_SYSERROR, "execvp() failed"); exit(1); } /* }}} */ @@ -143,6 +133,9 @@ int fpm_pctl_kill(pid_t pid, int how) /* {{{ */ case FPM_PCTL_CONT : s = SIGCONT; break; + case FPM_PCTL_QUIT : + s = SIGQUIT; + break; default : break; } @@ -161,7 +154,7 @@ static void fpm_pctl_kill_all(int signo) /* {{{ */ for (child = wp->children; child; child = child->next) { int res = kill(child->pid, signo); - zlog(ZLOG_STUFF, ZLOG_DEBUG, "[pool %s] sending signal %d %s to child %d", + zlog(ZLOG_DEBUG, "[pool %s] sending signal %d %s to child %d", child->wp->config->name, signo, fpm_signal_names[signo] ? fpm_signal_names[signo] : "", (int) child->pid); @@ -172,12 +165,12 @@ static void fpm_pctl_kill_all(int signo) /* {{{ */ } if (alive_children) { - zlog(ZLOG_STUFF, ZLOG_DEBUG, "%d child(ren) still alive", alive_children); + zlog(ZLOG_DEBUG, "%d child(ren) still alive", alive_children); } } /* }}} */ -static void fpm_pctl_action_next(struct event_base *base) /* {{{ */ +static void fpm_pctl_action_next() /* {{{ */ { int sig, timeout; @@ -203,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 : @@ -227,7 +220,7 @@ void fpm_pctl(int new_state, int action, struct event_base *base) /* {{{ */ if (new_state == FPM_PCTL_STATE_TERMINATING) break; case FPM_PCTL_STATE_TERMINATING : /* nothing can override 'terminating' state */ - zlog(ZLOG_STUFF, ZLOG_DEBUG, "not switching to '%s' state, because already in '%s' state", + zlog(ZLOG_DEBUG, "not switching to '%s' state, because already in '%s' state", fpm_state_names[new_state], fpm_state_names[fpm_state]); return; } @@ -235,11 +228,11 @@ void fpm_pctl(int new_state, int action, struct event_base *base) /* {{{ */ fpm_signal_sent = 0; fpm_state = new_state; - zlog(ZLOG_STUFF, ZLOG_DEBUG, "switching to '%s' state", fpm_state_names[fpm_state]); + zlog(ZLOG_DEBUG, "switching to '%s' state", fpm_state_names[fpm_state]); /* 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(); @@ -255,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; } @@ -314,51 +307,49 @@ 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; - struct fpm_child_s *last_idle_child = NULL; - int i; for (wp = fpm_worker_all_pools; wp; wp = wp->next) { struct fpm_child_s *child; + struct fpm_child_s *last_idle_child = NULL; int idle = 0; int active = 0; + int children_to_fork; + unsigned cur_lq; if (wp->config == NULL) continue; for (child = wp->children; child; child = child->next) { - int ret = fpm_request_is_idle(child); - if (ret == 1) { + if (fpm_request_is_idle(child)) { if (last_idle_child == NULL) { last_idle_child = child; } else { - if (child->started.tv_sec < last_idle_child->started.tv_sec) { + if (timercmp(&child->started, &last_idle_child->started, <)) { last_idle_child = child; } } idle++; - } else if (ret == 0) { + } else { active++; } } - if ((active + idle) != wp->running_children) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] unable to retrieve process activity of one or more child(ren). Will try again later.", wp->config->name); - continue; - } - /* update status structure for all PMs */ - fpm_status_update_activity(wp->shm_status, idle, active, idle + active, 0); + if (0 > fpm_socket_get_listening_queue(wp, &cur_lq, NULL)) { + cur_lq = 0; + } + fpm_status_update_activity(wp->shm_status, idle, active, idle + active, cur_lq, wp->listening_queue_len, 0); /* the rest is only used by PM_STYLE_DYNAMIC */ if (wp->config->pm != PM_STYLE_DYNAMIC) continue; - zlog(ZLOG_STUFF, ZLOG_DEBUG, "[pool %s] currently %d active children, %d spare children, %d running children. Spawning rate %d", wp->config->name, active, idle, wp->running_children, wp->idle_spawn_rate); + zlog(ZLOG_DEBUG, "[pool %s] currently %d active children, %d spare children, %d running children. Spawning rate %d", wp->config->name, active, idle, wp->running_children, wp->idle_spawn_rate); if (idle > wp->config->pm_max_spare_servers && last_idle_child) { last_idle_child->idle_kill = 1; - fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_TERM); + fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT); wp->idle_spawn_rate = 1; continue; } @@ -366,7 +357,8 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct if (idle < wp->config->pm_min_spare_servers) { if (wp->running_children >= wp->config->pm_max_children) { if (!wp->warn_max_children) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] server reached max_children setting (%d), consider raising it", wp->config->name, wp->config->pm_max_children); + fpm_status_increment_max_children_reached(wp->shm_status); + 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; } wp->idle_spawn_rate = 1; @@ -374,17 +366,18 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct } if (wp->idle_spawn_rate >= 8) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] seems busy (you may need to increase start_servers, or min/max_spare_servers), spawning %d children, there are %d idle, and %d total children", wp->config->name, wp->idle_spawn_rate, idle, wp->running_children); + zlog(ZLOG_WARNING, "[pool %s] seems busy (you may need to increase start_servers, or min/max_spare_servers), spawning %d children, there are %d idle, and %d total children", wp->config->name, wp->idle_spawn_rate, idle, wp->running_children); } /* compute the number of idle process to spawn */ - i = MIN(wp->idle_spawn_rate, wp->config->pm_min_spare_servers - idle); + children_to_fork = MIN(wp->idle_spawn_rate, wp->config->pm_min_spare_servers - idle); /* get sure it won't exceed max_children */ - i = MIN(i, wp->config->pm_max_children - wp->running_children); - if (i <= 0) { + children_to_fork = MIN(children_to_fork, wp->config->pm_max_children - wp->running_children); + if (children_to_fork <= 0) { if (!wp->warn_max_children) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] server reached max_children setting (%d), consider raising it", wp->config->name, wp->config->pm_max_children); + fpm_status_increment_max_children_reached(wp->shm_status); + 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; } wp->idle_spawn_rate = 1; @@ -392,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, i, 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 @@ -401,7 +394,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct return; } - zlog(ZLOG_STUFF, ZLOG_DEBUG, "[pool %s] %d child(ren) have been created dynamically", wp->config->name, i); + zlog(ZLOG_DEBUG, "[pool %s] %d child(ren) have been created dynamically", wp->config->name, children_to_fork); /* Double the spawn rate for the next iteration */ if (wp->idle_spawn_rate < FPM_MAX_SPAWN_RATE) { @@ -414,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 @@ -453,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 8834d5f3b..36577097c 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(); @@ -38,7 +42,8 @@ enum { enum { FPM_PCTL_TERM, FPM_PCTL_STOP, - FPM_PCTL_CONT + FPM_PCTL_CONT, + FPM_PCTL_QUIT }; #endif diff --git a/sapi/fpm/fpm/fpm_request.c b/sapi/fpm/fpm/fpm_request.c index 8fff8bea3..590548e57 100644 --- a/sapi/fpm/fpm/fpm_request.c +++ b/sapi/fpm/fpm/fpm_request.c @@ -136,7 +136,7 @@ void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, fpm_trace_signal(child->pid); - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] child %d, script '%s' executing too slow (%d.%06d sec), logging", + zlog(ZLOG_WARNING, "[pool %s] child %d, script '%s' executing too slow (%d.%06d sec), logging", child->wp->config->name, (int) child->pid, purified_script_filename, (int) tv.tv_sec, (int) tv.tv_usec); } else @@ -145,7 +145,7 @@ void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename)); fpm_pctl_kill(child->pid, FPM_PCTL_TERM); - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] child %d, script '%s' execution timed out (%d.%06d sec), terminating", + zlog(ZLOG_WARNING, "[pool %s] child %d, script '%s' execution timed out (%d.%06d sec), terminating", child->wp->config->name, (int) child->pid, purified_script_filename, (int) tv.tv_sec, (int) tv.tv_usec); } } @@ -154,16 +154,11 @@ void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, int fpm_request_is_idle(struct fpm_child_s *child) /* {{{ */ { - struct fpm_shm_slot_s *slot; - struct fpm_shm_slot_s slot_c; + struct fpm_shm_slot_s slot; - slot = fpm_shm_slot(child); - if (!fpm_shm_slots_acquire(slot, 1)) { - return -1; - } + /* no need in atomicity here */ + slot = *fpm_shm_slot(child); - slot_c = *slot; - fpm_shm_slots_release(slot); - return(!slot_c.accepted.tv_sec && !slot_c.accepted.tv_usec ? 1 : 0); + return slot.request_stage == FPM_REQUEST_ACCEPTING; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_shm.c b/sapi/fpm/fpm/fpm_shm.c index cfacde204..5f4040990 100644 --- a/sapi/fpm/fpm/fpm_shm.c +++ b/sapi/fpm/fpm/fpm_shm.c @@ -30,7 +30,7 @@ struct fpm_shm_s *fpm_shm_alloc(size_t sz) /* {{{ */ shm->mem = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); if (!shm->mem) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "mmap(MAP_ANONYMOUS | MAP_SHARED) failed"); + zlog(ZLOG_SYSERROR, "mmap(MAP_ANONYMOUS | MAP_SHARED) failed"); free(shm); return 0; } diff --git a/sapi/fpm/fpm/fpm_signals.c b/sapi/fpm/fpm/fpm_signals.c index eb2528b0e..aea69750b 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_STUFF, ZLOG_SYSERROR, "socketpair() failed"); + zlog(ZLOG_SYSERROR, "socketpair() failed"); return -1; } if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed"); + zlog(ZLOG_SYSERROR, "fd_set_blocked() failed"); return -1; } if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fcntl(F_SETFD, FD_CLOEXEC) failed"); + zlog(ZLOG_SYSERROR, "fcntl(F_SETFD, FD_CLOEXEC) failed"); return -1; } @@ -207,7 +207,7 @@ int fpm_signals_init_main() /* {{{ */ 0 > sigaction(SIGCHLD, &act, 0) || 0 > sigaction(SIGQUIT, &act, 0)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed"); + zlog(ZLOG_SYSERROR, "sigaction() failed"); 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_STUFF, ZLOG_SYSERROR, "sigaction() failed"); + zlog(ZLOG_SYSERROR, "sigaction() failed"); return -1; } return 0; diff --git a/sapi/fpm/fpm/fpm_sockets.c b/sapi/fpm/fpm/fpm_sockets.c index 21baf053c..baa9f9803 100644 --- a/sapi/fpm/fpm/fpm_sockets.c +++ b/sapi/fpm/fpm/fpm_sockets.c @@ -49,7 +49,7 @@ static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockadd ret = getaddrinfo(node, service, &hints, &res); if (ret != 0) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n", + zlog(ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n", node, service ? ":" : "", service ? service : "", gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : ""); return -1; @@ -65,7 +65,7 @@ enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 }; static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */ { - int i; + unsigned i; char *env_value = 0; int p = 0; struct listening_socket_s *ls = sockets_list.data; @@ -124,7 +124,7 @@ static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int typ case FPM_GET_USE_SOCKET : { - int i; + unsigned i; struct listening_socket_s *ls = sockets_list.data; for (i = 0; i < sockets_list.used; i++, ls++) { @@ -171,7 +171,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_STUFF, ZLOG_SYSERROR, "socket() failed"); + zlog(ZLOG_SYSERROR, "socket() failed"); return -1; } @@ -179,28 +179,32 @@ static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct if (wp->listen_address_domain == FPM_AF_UNIX) { unlink( ((struct sockaddr_un *) sa)->sun_path); + saved_umask = umask(0777 ^ wp->socket_mode); } - saved_umask = umask(0777 ^ wp->socket_mode); - if (0 > bind(sock, sa, socklen)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "bind() for address '%s' failed", wp->config->listen_address); + zlog(ZLOG_SYSERROR, "bind() for address '%s' failed", wp->config->listen_address); + if (wp->listen_address_domain == FPM_AF_UNIX) { + umask(saved_umask); + } return -1; } if (wp->listen_address_domain == FPM_AF_UNIX) { char *path = ((struct sockaddr_un *) sa)->sun_path; + + umask(saved_umask); + if (wp->socket_uid != -1 || wp->socket_gid != -1) { if (0 > chown(path, wp->socket_uid, wp->socket_gid)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chown() for address '%s' failed", wp->config->listen_address); + zlog(ZLOG_SYSERROR, "chown() for address '%s' failed", wp->config->listen_address); return -1; } } } - umask(saved_umask); if (0 > listen(sock, wp->config->listen_backlog)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "listen() for address '%s' failed", wp->config->listen_address); + zlog(ZLOG_SYSERROR, "listen() for address '%s' failed", wp->config->listen_address); return -1; } return sock; @@ -253,7 +257,7 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* } if (port == 0) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "invalid port value '%s'", port_str); + zlog(ZLOG_ERROR, "invalid port value '%s'", port_str); return -1; } @@ -265,7 +269,7 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) { return -1; } - zlog(ZLOG_STUFF, ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr)); + zlog(ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr)); } } else { sa_in.sin_addr.s_addr = htonl(INADDR_ANY); @@ -290,7 +294,7 @@ static int fpm_socket_af_unix_listening_socket(struct fpm_worker_pool_s *wp) /* int fpm_sockets_init_main() /* {{{ */ { - int i; + unsigned i; struct fpm_worker_pool_s *wp; char *inherited = getenv("FPM_SOCKETS"); struct listening_socket_s *ls; @@ -314,7 +318,7 @@ int fpm_sockets_init_main() /* {{{ */ *eq = '\0'; fd_no = atoi(eq + 1); type = fpm_sockets_domain_from_address(inherited); - zlog(ZLOG_STUFF, ZLOG_NOTICE, "using inherited socket fd=%d, \"%s\"", fd_no, inherited); + zlog(ZLOG_NOTICE, "using inherited socket fd=%d, \"%s\"", fd_no, inherited); fpm_sockets_hash_op(fd_no, 0, inherited, type, FPM_STORE_SOCKET); } @@ -340,6 +344,10 @@ int fpm_sockets_init_main() /* {{{ */ break; } + if (0 > fpm_socket_get_listening_queue(wp, NULL, (unsigned *) &wp->listening_queue_len)) { + wp->listening_queue_len = -1; + } + if (wp->listening_socket == -1) { return -1; } @@ -369,3 +377,76 @@ int fpm_sockets_init_main() /* {{{ */ } /* }}} */ +#if HAVE_FPM_LQ + +#ifdef HAVE_LQ_TCP_INFO + +#include <netinet/tcp.h> + +int fpm_socket_get_listening_queue(struct fpm_worker_pool_s *wp, unsigned *cur_lq, unsigned *max_lq) +{ + if (wp->listen_address_domain != FPM_AF_INET) { + return -1; + } + + struct tcp_info info; + socklen_t len = sizeof(info); + + if (0 > getsockopt(wp->listening_socket, IPPROTO_TCP, TCP_INFO, &info, &len)) { + return -1; + } + + /* kernel >= 2.6.24 return non-zero here, that means operation is supported */ + if (info.tcpi_sacked == 0) { + return -1; + } + + if (cur_lq) { + *cur_lq = info.tcpi_unacked; + } + + if (max_lq) { + *max_lq = info.tcpi_sacked; + } + + return 0; +} + +#endif + +#ifdef HAVE_LQ_SO_LISTENQ + +int fpm_socket_get_listening_queue(struct fpm_worker_pool_s *wp, unsigned *cur_lq, unsigned *max_lq) +{ + int val; + socklen_t len = sizeof(val); + + if (cur_lq) { + if (0 > getsockopt(wp->listening_socket, SOL_SOCKET, SO_LISTENQLEN, &val, &len)) { + return -1; + } + + *cur_lq = val; + } + + if (max_lq) { + if (0 > getsockopt(wp->listening_socket, SOL_SOCKET, SO_LISTENQLIMIT, &val, &len)) { + return -1; + } + + *max_lq = val; + } + + return 0; +} + +#endif + +#else + +int fpm_socket_get_listening_queue(struct fpm_worker_pool_s *wp, unsigned *cur_lq, unsigned *max_lq) +{ + return -1; +} + +#endif diff --git a/sapi/fpm/fpm/fpm_sockets.h b/sapi/fpm/fpm/fpm_sockets.h index d9e283d5a..b74fc234c 100644 --- a/sapi/fpm/fpm/fpm_sockets.h +++ b/sapi/fpm/fpm/fpm_sockets.h @@ -10,8 +10,18 @@ #include "fpm_worker_pool.h" +/* + On FreeBSD and OpenBSD, backlog negative values are truncated to SOMAXCONN +*/ +#if (__FreeBSD__) || (__OpenBSD__) +#define FPM_BACKLOG_DEFAULT -1 +#else +#define FPM_BACKLOG_DEFAULT 128 +#endif + enum fpm_address_domain fpm_sockets_domain_from_address(char *addr); int fpm_sockets_init_main(); +int fpm_socket_get_listening_queue(struct fpm_worker_pool_s *wp, unsigned *cur_lq, unsigned *max_lq); static inline int fd_set_blocked(int fd, int blocked) /* {{{ */ diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index ebc73cdc6..76daf7d10 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -1,5 +1,5 @@ - /* $Id: fpm_status.c 298380 2010-04-23 15:09:28Z fat $ */ + /* $Id: fpm_status.c 305281 2010-11-11 21:38:18Z fat $ */ /* (c) 2009 Jerome Loyet */ #include "php.h" @@ -20,13 +20,13 @@ static char *fpm_status_pong= NULL; int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ { if (!wp || !wp->config) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "unable to init fpm_status because conf structure is NULL"); + zlog(ZLOG_ERROR, "unable to init fpm_status because conf structure is NULL"); return -1; } if (wp->config->pm_status_path || wp->config->ping_path) { if (wp->config->pm_status_path) { if (!wp->shm_status) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] unable to init fpm_status because the dedicated SHM has not been set", wp->config->name); + zlog(ZLOG_ERROR, "[pool %s] unable to init fpm_status because the dedicated SHM has not been set", wp->config->name); return -1; } fpm_status_shm = wp->shm_status; @@ -37,7 +37,7 @@ int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ } if (wp->config->ping_path) { if (!wp->config->ping_response) { - zlog(ZLOG_STUFF, 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 pong is not set.", wp->config->name, wp->config->ping_path); return -1; } fpm_status_ping = strdup(wp->config->ping_path); @@ -99,7 +99,41 @@ void fpm_status_update_accepted_conn(struct fpm_shm_s *shm, unsigned long int ac } /* }}} */ -void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int total, int clear_last_update) /* {{{ */ +void fpm_status_increment_max_children_reached(struct fpm_shm_s *shm) /* {{{ */ +{ + struct fpm_status_s status; + + if (!shm) shm = fpm_status_shm; + if (!shm || !shm->mem) return; + + /* one shot operation */ + status = *(struct fpm_status_s *)shm->mem; + + status.max_children_reached++; + + /* one shot operation */ + *(struct fpm_status_s *)shm->mem = status; +} +/* }}} */ + +void fpm_status_update_max_children_reached(struct fpm_shm_s *shm, unsigned int max_children_reached) /* {{{ */ +{ + struct fpm_status_s status; + + if (!shm) shm = fpm_status_shm; + if (!shm || !shm->mem) return; + + /* one shot operation */ + status = *(struct fpm_status_s *)shm->mem; + + status.max_children_reached = max_children_reached; + + /* one shot operation */ + *(struct fpm_status_s *)shm->mem = status; +} +/* }}} */ + +void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int total, unsigned cur_lq, int max_lq, int clear_last_update) /* {{{ */ { struct fpm_status_s status; @@ -112,6 +146,8 @@ void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int status.idle = idle; status.active = active; status.total = total; + status.cur_lq = cur_lq; + status.max_lq = max_lq; if (clear_last_update) { memset(&status.last_update, 0, sizeof(status.last_update)); } else { @@ -130,15 +166,30 @@ static void fpm_status_handle_status_txt(struct fpm_status_s *status, char **out } spprintf(output, 0, - "accepted conn: %lu\n" - "pool: %s\n" - "process manager: %s\n" - "idle processes: %d\n" - "active processes: %d\n" - "total processes: %d\n", - status->accepted_conn, fpm_status_pool, status->pm == PM_STYLE_STATIC ? "static" : "dynamic", status->idle, status->active, status->total); - - spprintf(content_type, 0, "text/plain"); + "pool: %s\n" + "process manager: %s\n" + "accepted conn: %lu\n" +#if HAVE_FPM_LQ + "listen queue len: %u\n" + "max listen queue len: %d\n" +#endif + "idle processes: %d\n" + "active processes: %d\n" + "total processes: %d\n" + "max children reached: %u\n", + fpm_status_pool, + status->pm == PM_STYLE_STATIC ? "static" : "dynamic", + status->accepted_conn, +#if HAVE_FPM_LQ + status->cur_lq, + status->max_lq, +#endif + status->idle, + status->active, + status->total, + status->max_children_reached); + + spprintf(content_type, 0, "Content-Type: text/plain"); } /* }}} */ @@ -150,16 +201,31 @@ static void fpm_status_handle_status_html(struct fpm_status_s *status, char **ou spprintf(output, 0, "<table>\n" - "<tr><th>accepted conn</th><td>%lu</td></tr>\n" "<tr><th>pool</th><td>%s</td></tr>\n" "<tr><th>process manager</th><td>%s</td></tr>\n" + "<tr><th>accepted conn</th><td>%lu</td></tr>\n" +#if HAVE_FPM_LQ + "<tr><th>listen queue len</th><td>%u</td></tr>\n" + "<tr><th>max listen queue len</th><td>%d</td></tr>\n" +#endif "<tr><th>idle processes</th><td>%d</td></tr>\n" "<tr><th>active processes</th><td>%d</td></tr>\n" "<tr><th>total processes</th><td>%d</td></tr>\n" + "<tr><th>max children reached</th><td>%u</td></tr>\n" "</table>", - status->accepted_conn, fpm_status_pool, status->pm == PM_STYLE_STATIC ? "static" : "dynamic", status->idle, status->active, status->total); - - spprintf(content_type, 0, "text/html"); + fpm_status_pool, + status->pm == PM_STYLE_STATIC ? "static" : "dynamic", + status->accepted_conn, +#if HAVE_FPM_LQ + status->cur_lq, + status->max_lq, +#endif + status->idle, + status->active, + status->total, + status->max_children_reached); + + spprintf(content_type, 0, "Content-Type: text/html"); } /* }}} */ @@ -171,16 +237,31 @@ static void fpm_status_handle_status_json(struct fpm_status_s *status, char **ou spprintf(output, 0, "{" - "\"accepted conn\":%lu," "\"pool\":\"%s\"," "\"process manager\":\"%s\"," + "\"accepted conn\":%lu," +#if HAVE_FPM_LQ + "\"listen queue len\":%u," + "\"max listen queue len\":%d," +#endif "\"idle processes\":%d," "\"active processes\":%d," - "\"total processes\":%d" + "\"total processes\":%d," + "\"max children reached\":%u" "}", - status->accepted_conn, fpm_status_pool, status->pm == PM_STYLE_STATIC ? "static" : "dynamic", status->idle, status->active, status->total); - - spprintf(content_type, 0, "application/jsonrequest"); + fpm_status_pool, + status->pm == PM_STYLE_STATIC ? "static" : "dynamic", + status->accepted_conn, +#if HAVE_FPM_LQ + status->cur_lq, + status->max_lq, +#endif + status->idle, + status->active, + status->total, + status->max_children_reached); + + spprintf(content_type, 0, "Content-Type: application/json"); } /* }}} */ @@ -226,7 +307,7 @@ int fpm_status_handle_status(char *uri, char *query_string, char **output, char } if (!*output || !content_type) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] unable to allocate status ouput buffer", fpm_status_pool); + zlog(ZLOG_ERROR, "[pool %s] unable to allocate status ouput buffer", fpm_status_pool); return 1; } diff --git a/sapi/fpm/fpm/fpm_status.h b/sapi/fpm/fpm/fpm_status.h index a079bd0df..4e9c50705 100644 --- a/sapi/fpm/fpm/fpm_status.h +++ b/sapi/fpm/fpm/fpm_status.h @@ -1,5 +1,5 @@ - /* $Id: fpm_status.h 298380 2010-04-23 15:09:28Z fat $ */ + /* $Id: fpm_status.h 305267 2010-11-11 02:34:47Z fat $ */ /* (c) 2009 Jerome Loyet */ #ifndef FPM_STATUS_H @@ -14,15 +14,20 @@ struct fpm_status_s { int idle; int active; int total; + unsigned cur_lq; + int max_lq; unsigned long int accepted_conn; + unsigned int max_children_reached; struct timeval last_update; }; int fpm_status_init_child(struct fpm_worker_pool_s *wp); -void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int total, int clear_last_update); +void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int total, unsigned cur_lq, int max_lq, int clear_last_update); void fpm_status_update_accepted_conn(struct fpm_shm_s *shm, unsigned long int accepted_conn); void fpm_status_increment_accepted_conn(struct fpm_shm_s *shm); void fpm_status_set_pm(struct fpm_shm_s *shm, int pm); +void fpm_status_update_max_children_reached(struct fpm_shm_s *shm, unsigned int max_children_reached); +void fpm_status_increment_max_children_reached(struct fpm_shm_s *shm); int fpm_status_handle_status(char *uri, char *query_string, char **output, char **content_type); char* fpm_status_handle_ping(char *uri); diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index d18e1d532..571f3074b 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -26,12 +26,12 @@ int fpm_stdio_init_main() /* {{{ */ int fd = open("/dev/null", O_RDWR); if (0 > fd) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"/dev/null\") failed"); + zlog(ZLOG_SYSERROR, "open(\"/dev/null\") failed"); return -1; } if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed"); + zlog(ZLOG_SYSERROR, "dup2() failed"); return -1; } close(fd); @@ -41,17 +41,16 @@ int fpm_stdio_init_main() /* {{{ */ int fpm_stdio_init_final() /* {{{ */ { - zlog_set_level(fpm_globals.log_level); 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 */ if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed"); + zlog(ZLOG_SYSERROR, "dup2() failed"); return -1; } } - zlog_set_fd(fpm_globals.error_log_fd); } + zlog_set_launched(); return 0; } /* }}} */ @@ -64,7 +63,7 @@ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ if (wp->listening_socket != STDIN_FILENO) { if (0 > dup2(wp->listening_socket, STDIN_FILENO)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed"); + zlog(ZLOG_SYSERROR, "dup2() failed"); return -1; } } @@ -72,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); @@ -94,10 +105,10 @@ static void fpm_stdio_child_said(int fd, short which, void *arg) /* {{{ */ } else { /* error or pipe is closed */ if (res < 0) { /* error */ - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed"); + zlog(ZLOG_SYSERROR, "read() failed"); } - fpm_event_del(ev); + fpm_event_del(event); is_last_message = 1; if (is_stdout) { @@ -140,7 +151,7 @@ static void fpm_stdio_child_said(int fd, short which, void *arg) /* {{{ */ *nl = '\0'; } - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] child %d said into %s: \"%s\"%s", child->wp->config->name, + zlog(ZLOG_WARNING, "[pool %s] child %d said into %s: \"%s\"%s", child->wp->config->name, (int) child->pid, is_stdout ? "stdout" : "stderr", buf, is_last_message ? ", pipe is closed" : ""); if (nl) { @@ -164,18 +175,18 @@ int fpm_stdio_prepare_pipes(struct fpm_child_s *child) /* {{{ */ } if (0 > pipe(fd_stdout)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed"); + zlog(ZLOG_SYSERROR, "pipe() failed"); return -1; } if (0 > pipe(fd_stderr)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed"); + zlog(ZLOG_SYSERROR, "pipe() failed"); 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_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed"); + zlog(ZLOG_SYSERROR, "fd_set_blocked() failed"); close(fd_stdout[0]); close(fd_stdout[1]); close(fd_stderr[0]); close(fd_stderr[1]); return -1; @@ -184,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; @@ -196,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; } /* }}} */ @@ -237,7 +251,7 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (0 > fd) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log); + zlog(ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log); return -1; } @@ -251,6 +265,9 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */ } else { fpm_globals.error_log_fd = fd; + if (fpm_global_config.daemonize) { + zlog_set_fd(fpm_globals.error_log_fd); + } } fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); return 0; diff --git a/sapi/fpm/fpm/fpm_stdio.h b/sapi/fpm/fpm/fpm_stdio.h index 5d53a26e8..d3d61e46b 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/fpm/fpm_trace_mach.c b/sapi/fpm/fpm/fpm_trace_mach.c index 47b44ff82..fe26fd9e2 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_STUFF, ZLOG_ERROR, "mach_vm_read() failed: %s (%d)", mach_error_string(kr), kr); + zlog(ZLOG_ERROR, "mach_vm_read() failed: %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_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed"); + zlog(ZLOG_SYSERROR, "kill(SIGSTOP) failed"); return -1; } return 0; @@ -65,7 +65,7 @@ int fpm_trace_ready(pid_t pid) /* {{{ */ if (kr == KERN_FAILURE) { msg = " It seems that master process does not have enough privileges to trace processes."; } - zlog(ZLOG_STUFF, ZLOG_ERROR, "task_for_pid() failed: %s (%d)%s", mach_error_string(kr), kr, msg); + zlog(ZLOG_ERROR, "task_for_pid() failed: %s (%d)%s", mach_error_string(kr), kr, msg); return -1; } return 0; diff --git a/sapi/fpm/fpm/fpm_trace_pread.c b/sapi/fpm/fpm/fpm_trace_pread.c index d2f7e5a05..eda84928e 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_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed"); + zlog(ZLOG_SYSERROR, "kill(SIGSTOP) failed"); 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_STUFF, ZLOG_SYSERROR, "open(%s) failed", buf); + zlog(ZLOG_SYSERROR, "open(%s) failed", buf); return -1; } return 0; @@ -58,7 +58,7 @@ int fpm_trace_close(pid_t pid) /* {{{ */ int fpm_trace_get_long(long addr, long *data) /* {{{ */ { if (sizeof(*data) != pread(mem_file, (void *) data, sizeof(*data), (uintptr_t) addr)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pread() failed"); + zlog(ZLOG_SYSERROR, "pread() failed"); return -1; } return 0; diff --git a/sapi/fpm/fpm/fpm_trace_ptrace.c b/sapi/fpm/fpm/fpm_trace_ptrace.c index 86cf52830..395c1ac08 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_STUFF, ZLOG_SYSERROR, "ptrace(ATTACH) failed"); + zlog(ZLOG_SYSERROR, "ptrace(ATTACH) failed"); 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_STUFF, ZLOG_SYSERROR, "ptrace(DETACH) failed"); + zlog(ZLOG_SYSERROR, "ptrace(DETACH) failed"); 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_STUFF, ZLOG_SYSERROR, "ptrace(PT_IO) failed"); + zlog(ZLOG_SYSERROR, "ptrace(PT_IO) failed"); return -1; } #else errno = 0; *data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0); if (errno) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PEEKDATA) failed"); + zlog(ZLOG_SYSERROR, "ptrace(PEEKDATA) failed"); return -1; } #endif diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index 395d703d1..d63ea4d5b 100644 --- a/sapi/fpm/fpm/fpm_unix.c +++ b/sapi/fpm/fpm/fpm_unix.c @@ -45,7 +45,7 @@ int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */ pwd = getpwnam(c->listen_owner); if (!pwd) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, c->listen_owner); + zlog(ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, c->listen_owner); return -1; } @@ -58,7 +58,7 @@ int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */ grp = getgrnam(c->listen_group); if (!grp) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, c->listen_group); + zlog(ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, c->listen_group); return -1; } wp->socket_gid = grp->gr_gid; @@ -84,7 +84,7 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ pwd = getpwnam(wp->config->user); if (!pwd) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, wp->config->user); + zlog(ZLOG_ERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, wp->config->user); return -1; } @@ -104,7 +104,7 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ grp = getgrnam(wp->config->group); if (!grp) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, wp->config->group); + zlog(ZLOG_ERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, wp->config->group); return -1; } wp->set_gid = grp->gr_gid; @@ -113,19 +113,19 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ #ifndef I_REALLY_WANT_ROOT_PHP if (wp->set_uid == 0 || wp->set_gid == 0) { - zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] please specify user and group other than root", wp->config->name); + zlog(ZLOG_ERROR, "[pool %s] please specify user and group other than root", wp->config->name); return -1; } #endif } else { /* not root */ if (wp->config->user && *wp->config->user) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'user' directive is ignored", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'user' directive is ignored", wp->config->name); } if (wp->config->group && *wp->config->group) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'group' directive is ignored", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'group' directive is ignored", wp->config->name); } if (wp->config->chroot && *wp->config->chroot) { - zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'chroot' directive is ignored", wp->config->name); + zlog(ZLOG_WARNING, "[pool %s] 'chroot' directive is ignored", wp->config->name); } { /* set up HOME and USER anyway */ @@ -153,7 +153,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_STUFF, ZLOG_SYSERROR, "[pool %s] setrlimit(RLIMIT_NOFILE, %d) failed (%d)", wp->config->name, wp->config->rlimit_files, errno); + zlog(ZLOG_SYSERROR, "[pool %s] setrlimit(RLIMIT_NOFILE, %d) failed (%d)", wp->config->name, wp->config->rlimit_files, errno); } } @@ -163,13 +163,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_STUFF, ZLOG_SYSERROR, "[pool %s] setrlimit(RLIMIT_CORE, %d) failed (%d)", wp->config->name, wp->config->rlimit_core, errno); + zlog(ZLOG_SYSERROR, "[pool %s] setrlimit(RLIMIT_CORE, %d) failed (%d)", wp->config->name, wp->config->rlimit_core, errno); } } if (is_root && wp->config->chroot && *wp->config->chroot) { if (0 > chroot(wp->config->chroot)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "[pool %s] chroot(%s) failed", wp->config->name, wp->config->chroot); + zlog(ZLOG_SYSERROR, "[pool %s] chroot(%s) failed", wp->config->name, wp->config->chroot); return -1; } made_chroot = 1; @@ -177,7 +177,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_STUFF, ZLOG_SYSERROR, "[pool %s] chdir(%s) failed", wp->config->name, wp->config->chdir); + zlog(ZLOG_SYSERROR, "[pool %s] chdir(%s) failed", wp->config->name, wp->config->chdir); return -1; } } else if (made_chroot) { @@ -187,17 +187,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_STUFF, ZLOG_SYSERROR, "[pool %s] setgid(%d) failed", wp->config->name, wp->set_gid); + zlog(ZLOG_SYSERROR, "[pool %s] setgid(%d) failed", wp->config->name, wp->set_gid); return -1; } } if (wp->set_uid) { if (0 > initgroups(wp->config->user, wp->set_gid)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "[pool %s] initgroups(%s, %d) failed", wp->config->name, wp->config->user, wp->set_gid); + zlog(ZLOG_SYSERROR, "[pool %s] initgroups(%s, %d) failed", wp->config->name, wp->config->user, wp->set_gid); return -1; } if (0 > setuid(wp->set_uid)) { - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "[pool %s] setuid(%d) failed", wp->config->name, wp->set_uid); + zlog(ZLOG_SYSERROR, "[pool %s] setuid(%d) failed", wp->config->name, wp->set_uid); return -1; } } @@ -205,7 +205,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_STUFF, ZLOG_SYSERROR, "[pool %s] prctl(PR_SET_DUMPABLE) failed", wp->config->name); + zlog(ZLOG_SYSERROR, "[pool %s] prctl(PR_SET_DUMPABLE) failed", wp->config->name); } #endif @@ -224,7 +224,7 @@ int fpm_unix_init_main() /* {{{ */ if (fpm_global_config.daemonize) { switch (fork()) { case -1 : - zlog(ZLOG_STUFF, ZLOG_SYSERROR, "daemonized fork() failed"); + zlog(ZLOG_SYSERROR, "daemonized fork() failed"); return -1; case 0 : break; @@ -246,7 +246,7 @@ int fpm_unix_init_main() /* {{{ */ } } - fpm_stdio_init_final(); + zlog_set_level(fpm_globals.log_level); return 0; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_worker_pool.h b/sapi/fpm/fpm/fpm_worker_pool.h index 63aff9a55..7f240a20c 100644 --- a/sapi/fpm/fpm/fpm_worker_pool.h +++ b/sapi/fpm/fpm/fpm_worker_pool.h @@ -25,6 +25,7 @@ struct fpm_worker_pool_s { char *user, *home; /* for setting env USER and HOME */ enum fpm_address_domain listen_address_domain; int listening_socket; + int listening_queue_len; int set_uid, set_gid; /* config uid and gid */ int socket_uid, socket_gid, socket_mode; diff --git a/sapi/fpm/fpm/zlog.c b/sapi/fpm/fpm/zlog.c index fc3c0168e..b99ad850d 100644 --- a/sapi/fpm/fpm/zlog.c +++ b/sapi/fpm/fpm/zlog.c @@ -18,6 +18,7 @@ static int zlog_fd = -1; static int zlog_level = ZLOG_NOTICE; +static int launched = 0; static const char *level_names[] = { [ZLOG_DEBUG] = "DEBUG", @@ -27,6 +28,16 @@ static const char *level_names[] = { [ZLOG_ALERT] = "ALERT", }; +const char *zlog_get_level_name() /* {{{ */ +{ + return level_names[zlog_level]; +} +/* }}} */ + +void zlog_set_launched(void) { + launched = 1; +} + size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len) /* {{{ */ { struct tm t; @@ -58,7 +69,7 @@ int zlog_set_level(int new_value) /* {{{ */ } /* }}} */ -void zlog(const char *function, int line, int flags, const char *fmt, ...) /* {{{ */ +void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* {{{ */ { struct timeval tv; char buf[MAX_LINE_LENGTH]; @@ -110,6 +121,9 @@ void zlog(const char *function, int line, int flags, const char *fmt, ...) /* {{ 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 b5ac3d9bc..598c075e3 100644 --- a/sapi/fpm/fpm/zlog.h +++ b/sapi/fpm/fpm/zlog.h @@ -5,16 +5,18 @@ #ifndef ZLOG_H #define ZLOG_H 1 -#define ZLOG_STUFF __func__, __LINE__ +#define zlog(flags,...) zlog_ex(__func__, __LINE__, flags, __VA_ARGS__) struct timeval; int zlog_set_fd(int new_fd); int zlog_set_level(int new_value); +const char *zlog_get_level_name(); +void zlog_set_launched(void); size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len); -void zlog(const char *function, int line, int flags, const char *fmt, ...) +void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) __attribute__ ((format(printf,4,5))); enum { diff --git a/sapi/fpm/init.d.php-fpm.in b/sapi/fpm/init.d.php-fpm.in index dfeb69aeb..766d10207 100644 --- a/sapi/fpm/init.d.php-fpm.in +++ b/sapi/fpm/init.d.php-fpm.in @@ -2,8 +2,8 @@ ### BEGIN INIT INFO # Provides: php-fpm -# Required-Start: $all -# Required-Stop: $all +# Required-Start: $remote_fs $network +# Required-Stop: $remote_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts php-fpm diff --git a/sapi/fpm/php-fpm.1.in b/sapi/fpm/php-fpm.8.in index 3e940da1d..6c9c6d627 100644 --- a/sapi/fpm/php-fpm.1.in +++ b/sapi/fpm/php-fpm.8.in @@ -1,4 +1,4 @@ -.TH PHP-FPM 1 "2009" "The PHP Group" "Scripting Language" +.TH PHP-FPM 8 "2009" "The PHP Group" "Scripting Language" .SH NAME .TP 15 php-fpm \- PHP FastCGI Process Manager 'PHP-FPM' @@ -77,15 +77,28 @@ Show compiled in modules .PD 1 .B \-v Version number +.B \-\-prefix \fIpath\fP +.TP +.PD 1 +.B \-p +Specify alternative prefix path (the default is @php_fpm_prefix@) .TP .PD 0 .B \-\-fpm\-config \fIfile\fP .TP .PD 1 -.B \-\-y +.B \-y Specify alternative path to FastCGI process manager configuration file (the default is @php_fpm_sysconfdir@/php-fpm.conf) .TP .PD 0 +.B \-\-test +.TP +.PD 1 +.B \-t +Test FPM configuration file and exit +If called twice (-tt), the configuration is dumped before exiting. +.TP +.PD 0 .B \-\-zend\-extension \fIfile\fP .TP .PD 1 @@ -164,7 +177,7 @@ A List of active developers can be found here: And last but not least PHP was developed with the help of a huge amount of contributors all around the world. .SH VERSION INFORMATION -This manpage describes \fBphp\fP, version @PHP_VERSION@, \fBfpm\fP, version @fpm_version@. +This manpage describes \fBphp-fpm\fP, version @PHP_VERSION@. .SH COPYRIGHT Copyright \(co 1997\-2009 The PHP Group .PD 0 diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index 15024982b..314b7e5c5 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -3,12 +3,16 @@ ;;;;;;;;;;;;;;;;;;;;; ; All relative paths in this configuration file are relative to PHP's install -; prefix. +; prefix (@prefix@). This prefix can be dynamicaly changed by using the +; '-p' argument from the command line. ; Include one or more files. If glob(3) exists, it is used to include a bunch of ; files from a glob(3) pattern. This directive can be used everywhere in the ; file. -;include=@EXPANDED_SYSCONFDIR@/fpm.d/*.conf +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p arguement) +; - @prefix@ otherwise +;include=etc/fpm.d/*.conf ;;;;;;;;;;;;;;;;;; ; Global Options ; @@ -16,12 +20,14 @@ [global] ; Pid file +; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@ ; Default Value: none -;pid = @EXPANDED_LOCALSTATEDIR@/run/php-fpm.pid +;pid = run/php-fpm.pid ; Error log file -; Default Value: @EXPANDED_LOCALSTATEDIR@/log/php-fpm.log -;error_log = @EXPANDED_LOCALSTATEDIR@/log/php-fpm.log +; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@ +; Default Value: log/php-fpm.log +;error_log = log/php-fpm.log ; Log level ; Possible Values: alert, error, warning, notice, debug @@ -62,8 +68,23 @@ ; FPM can handle. Your system will tell you anyway :) ; Start a new pool named 'www'. +; the variable $pool can we used in any directive and will be replaced by the +; pool name ('www' here) [www] +; Per pool prefix +; It only applies on the following directives: +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or @php_fpm_prefix@) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + ; 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 @@ -75,7 +96,7 @@ listen = 127.0.0.1:9000 ; Set listen(2) backlog. A value of '-1' means unlimited. -; Default Value: -1 +; Default Value: 128 (-1 on FreeBSD and OpenBSD) ;listen.backlog = -1 ; List of ipv4 addresses of FastCGI clients which are allowed to connect. @@ -154,21 +175,25 @@ pm.max_children = 50 ; 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; -; pool - the name of the pool; -; process manager - static or dynamic; -; idle processes - the number of idle processes; -; active processes - the number of active processes; -; total processes - the number of idle + active processes. +; accepted conn - the number of request accepted by the pool; +; pool - the name of the pool; +; process manager - static or dynamic; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes. +; 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. ; Example output: -; accepted conn: 12073 -; pool: www -; process manager: static -; idle processes: 35 -; active processes: 65 -; total processes: 100 +; accepted conn: 12073 +; pool: www +; process manager: static +; idle processes: 35 +; active processes: 65 +; total processes: 100 +; max children reached: 1 ; By default the status page output is formatted as text/plain. Passing either ; 'html' or 'json' as a query string will return the corresponding output ; syntax. Example: @@ -212,8 +237,9 @@ pm.max_children = 50 ;request_slowlog_timeout = 0 ; The log file for slow requests -; Default Value: @EXPANDED_LOCALSTATEDIR@/log/php-fpm.log.slow -;slowlog = @EXPANDED_LOCALSTATEDIR@/log/php-fpm.log.slow +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/$pool.log.slow ; Set open file descriptor rlimit. ; Default Value: system defined value @@ -226,18 +252,24 @@ pm.max_children = 50 ; Chroot to this directory at the start. This value must be defined as an ; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. ; Note: chrooting is a great security feature and should be used whenever ; possible. However, all PHP paths will be relative to the chroot ; (error_log, sessions.save_path, ...). ; Default Value: not set ;chroot = -; Chdir to this directory at the start. This value must be an absolute path. +; Chdir to this directory at the start. +; Note: relative path can be used. ; Default Value: current directory or / when chroot ;chdir = /var/www ; 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 @@ -264,6 +296,9 @@ pm.max_children = 50 ; overwrite previously defined php.ini values, but will append the new value ; instead. +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or @prefix@) + ; Default Value: nothing is defined by default except the values in php.ini and ; specified at startup with the -d argument ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com |
