mirror of
https://github.com/php/php-src.git
synced 2024-11-24 10:24:11 +08:00
- Fixed bug #52501 (libevent made FPM crashed when forking -- libevent has been removed)
This commit is contained in:
parent
222e0bc0f6
commit
f13f4bc872
2
NEWS
2
NEWS
@ -261,6 +261,8 @@
|
||||
|
||||
- PHP-FPM SAPI:
|
||||
. Fixed inconsistent backlog default value (-1) in FPM on many systems. (fat)
|
||||
. Fixed bug #52501 (libevent made FPM crashed when forking -- libevent has
|
||||
been removed). (fat)
|
||||
. Fixed bug #52725 (gcc builtin atomic functions were sometimes used when they
|
||||
were not available). (fat)
|
||||
. Fixed bug #52693 (configuration file errors are not logged to stderr). (fat)
|
||||
|
@ -2,220 +2,9 @@ dnl
|
||||
dnl $Id$
|
||||
dnl
|
||||
|
||||
minimum_libevent_version="1.4.11"
|
||||
|
||||
PHP_ARG_ENABLE(fpm,,
|
||||
[ --enable-fpm EXPERIMENTAL: Enable building of the fpm SAPI executable], no, no)
|
||||
|
||||
dnl libevent check function {{{
|
||||
dnl @synopsis AC_LIB_EVENT([MINIMUM-VERSION])
|
||||
dnl
|
||||
dnl Test for the libevent library of a particular version (or newer).
|
||||
dnl Source: http://svn.apache.org/repos/asf/incubator/thrift/trunk/aclocal/ax_lib_event.m4
|
||||
dnl Modified: This file was modified for autoconf-2.13 and the PHP_ARG_WITH macro.
|
||||
dnl
|
||||
dnl If no path to the installed libevent is given, the macro will first try
|
||||
dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt,
|
||||
dnl and /opt/libevent.
|
||||
dnl If these all fail, it will try the $LIBEVENT_ROOT environment variable.
|
||||
dnl
|
||||
dnl This macro requires that #include <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],
|
||||
[
|
||||
@ -555,22 +344,6 @@ AC_MSG_CHECKING(for FPM build)
|
||||
if test "$PHP_FPM" != "no"; then
|
||||
AC_MSG_RESULT($PHP_FPM)
|
||||
|
||||
AC_LIB_EVENT([$minimum_libevent_version])
|
||||
|
||||
dnl check libevent build
|
||||
LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH"
|
||||
export LD_LIBRARY_PATH="$LIBEVENT_PATH:$LD_LIBRARY_PATH"
|
||||
|
||||
AC_MSG_CHECKING(whether libevent build works)
|
||||
PHP_TEST_BUILD(event_init, [
|
||||
AC_MSG_RESULT(yes)
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR([build test failed. Please check the config.log for details])
|
||||
], $LIBEVENT_LIBS)
|
||||
|
||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED"
|
||||
|
||||
AC_FPM_STDLIBS
|
||||
AC_FPM_PRCTL
|
||||
AC_FPM_CLOCK
|
||||
@ -619,10 +392,7 @@ if test "$PHP_FPM" != "no"; then
|
||||
PHP_FPM_TRACE_FILES="fpm/fpm_trace.c fpm/fpm_trace_$fpm_trace_type.c"
|
||||
fi
|
||||
|
||||
PHP_FPM_CFLAGS="$LIBEVENT_CFLAGS -I$abs_srcdir/sapi/fpm"
|
||||
|
||||
SAPI_EXTRA_LIBS="$LIBEVENT_LIBS"
|
||||
PHP_SUBST(SAPI_EXTRA_LIBS)
|
||||
PHP_FPM_CFLAGS="-I$abs_srcdir/sapi/fpm"
|
||||
|
||||
INSTALL_IT=":"
|
||||
PHP_FPM_FILES="fpm/fastcgi.c \
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
struct fpm_globals_s fpm_globals;
|
||||
|
||||
int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, struct event_base **base) /* {{{ */
|
||||
int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf) /* {{{ */
|
||||
{
|
||||
fpm_globals.argc = argc;
|
||||
fpm_globals.argv = argv;
|
||||
@ -40,7 +40,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, s
|
||||
0 > fpm_children_init_main() ||
|
||||
0 > fpm_sockets_init_main() ||
|
||||
0 > fpm_worker_pool_init_main() ||
|
||||
0 > fpm_event_init_main(base)) {
|
||||
0 > fpm_event_init_main()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf, s
|
||||
|
||||
/* children: return listening socket
|
||||
parent: never return */
|
||||
int fpm_run(int *max_requests, struct event_base *base) /* {{{ */
|
||||
int fpm_run(int *max_requests) /* {{{ */
|
||||
{
|
||||
struct fpm_worker_pool_s *wp;
|
||||
|
||||
@ -65,7 +65,7 @@ int fpm_run(int *max_requests, struct event_base *base) /* {{{ */
|
||||
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
|
||||
int is_parent;
|
||||
|
||||
is_parent = fpm_children_create_initial(wp, base);
|
||||
is_parent = fpm_children_create_initial(wp);
|
||||
|
||||
if (!is_parent) {
|
||||
goto run_child;
|
||||
@ -73,7 +73,7 @@ int fpm_run(int *max_requests, struct event_base *base) /* {{{ */
|
||||
}
|
||||
|
||||
/* run event loop forever */
|
||||
fpm_event_loop(base);
|
||||
fpm_event_loop();
|
||||
|
||||
run_child: /* only workers reach this point */
|
||||
|
||||
|
@ -6,11 +6,9 @@
|
||||
#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, char *prefix, int test_conf, struct event_base **base);
|
||||
int fpm_run(int *max_requests);
|
||||
int fpm_init(int argc, char **argv, char *config, char *prefix, int test_conf);
|
||||
|
||||
struct fpm_globals_s {
|
||||
pid_t parent_pid;
|
||||
|
@ -171,7 +171,7 @@ int fpm_children_free(struct fpm_child_s *child) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void fpm_children_bury(struct event_base *base) /* {{{ */
|
||||
void fpm_children_bury() /* {{{ */
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
@ -201,13 +201,13 @@ void fpm_children_bury(struct event_base *base) /* {{{ */
|
||||
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
const char *signame = fpm_signal_names[WTERMSIG(status)];
|
||||
const char *have_core = WCOREDUMP(status) ? " (core dumped)" : "";
|
||||
const char *have_core = WCOREDUMP(status) ? " - core dumped" : "";
|
||||
|
||||
if (signame == NULL) {
|
||||
signame = "";
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "on signal %d %s%s", WTERMSIG(status), signame, have_core);
|
||||
snprintf(buf, sizeof(buf), "on signal %d (%s%s)", WTERMSIG(status), signame, have_core);
|
||||
|
||||
/* if it's been killed because of dynamic process management
|
||||
* don't restart it automaticaly
|
||||
@ -277,19 +277,19 @@ void fpm_children_bury(struct event_base *base) /* {{{ */
|
||||
|
||||
zlog(ZLOG_WARNING, "failed processes threshold (%d in %d sec) is reached, initiating reload", fpm_global_config.emergency_restart_threshold, fpm_global_config.emergency_restart_interval);
|
||||
|
||||
fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
|
||||
}
|
||||
}
|
||||
|
||||
if (restart_child) {
|
||||
fpm_children_make(wp, 1 /* in event loop */, 1, 0, base);
|
||||
fpm_children_make(wp, 1 /* in event loop */, 1, 0);
|
||||
|
||||
if (fpm_globals.is_child) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zlog(ZLOG_ALERT, "oops, unknown child exited %s", buf);
|
||||
zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s", pid, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,15 +340,15 @@ static void fpm_child_resources_use(struct fpm_child_s *child) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void fpm_parent_resources_use(struct fpm_child_s *child, struct event_base *base) /* {{{ */
|
||||
static void fpm_parent_resources_use(struct fpm_child_s *child) /* {{{ */
|
||||
{
|
||||
fpm_shm_slots_parent_use_slot(child);
|
||||
fpm_stdio_parent_use_pipes(child, base);
|
||||
fpm_stdio_parent_use_pipes(child);
|
||||
fpm_child_link(child);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug, struct event_base *base) /* {{{ */
|
||||
int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug) /* {{{ */
|
||||
{
|
||||
int enough = 0;
|
||||
pid_t pid;
|
||||
@ -378,12 +378,8 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to
|
||||
switch (pid) {
|
||||
|
||||
case 0 :
|
||||
event_reinit(base); /* reinitialize event base after fork() */
|
||||
fpm_child_resources_use(child);
|
||||
fpm_globals.is_child = 1;
|
||||
if (in_event_loop) {
|
||||
fpm_event_exit_loop(base);
|
||||
}
|
||||
fpm_child_init(wp);
|
||||
return 0;
|
||||
|
||||
@ -398,7 +394,7 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to
|
||||
default :
|
||||
child->pid = pid;
|
||||
fpm_clock_get(&child->started);
|
||||
fpm_parent_resources_use(child, base);
|
||||
fpm_parent_resources_use(child);
|
||||
|
||||
zlog(is_debug ? ZLOG_DEBUG : ZLOG_NOTICE, "[pool %s] child %d started", wp->config->name, (int) pid);
|
||||
}
|
||||
@ -409,9 +405,9 @@ int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_children_create_initial(struct fpm_worker_pool_s *wp, struct event_base *base) /* {{{ */
|
||||
int fpm_children_create_initial(struct fpm_worker_pool_s *wp) /* {{{ */
|
||||
{
|
||||
return fpm_children_make(wp, 0 /* not in event loop yet */, 0, 1, base);
|
||||
return fpm_children_make(wp, 0 /* not in event loop yet */, 0, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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 {
|
||||
@ -46,22 +73,22 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */
|
||||
switch (c) {
|
||||
case 'C' : /* SIGCHLD */
|
||||
zlog(ZLOG_DEBUG, "received SIGCHLD");
|
||||
fpm_children_bury(base);
|
||||
fpm_children_bury();
|
||||
break;
|
||||
case 'I' : /* SIGINT */
|
||||
zlog(ZLOG_DEBUG, "received SIGINT");
|
||||
zlog(ZLOG_NOTICE, "Terminating ...");
|
||||
fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
|
||||
break;
|
||||
case 'T' : /* SIGTERM */
|
||||
zlog(ZLOG_DEBUG, "received SIGTERM");
|
||||
zlog(ZLOG_NOTICE, "Terminating ...");
|
||||
fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
|
||||
break;
|
||||
case 'Q' : /* SIGQUIT */
|
||||
zlog(ZLOG_DEBUG, "received SIGQUIT");
|
||||
zlog(ZLOG_NOTICE, "Finishing ...");
|
||||
fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET);
|
||||
break;
|
||||
case '1' : /* SIGUSR1 */
|
||||
zlog(ZLOG_DEBUG, "received SIGUSR1");
|
||||
@ -74,7 +101,7 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */
|
||||
case '2' : /* SIGUSR2 */
|
||||
zlog(ZLOG_DEBUG, "received SIGUSR2");
|
||||
zlog(ZLOG_NOTICE, "Reloading in progress ...");
|
||||
fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -86,57 +113,335 @@ static void fpm_got_signal(int fd, short ev, void *arg) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_event_init_main(struct event_base **base) /* {{{ */
|
||||
static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev) /* {{{ */
|
||||
{
|
||||
*base = event_base_new();
|
||||
if (!ev) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zlog(ZLOG_DEBUG, "libevent %s: using %s", event_get_version(), event_base_get_method(*base));
|
||||
while (queue) {
|
||||
if (queue->ev == ev) {
|
||||
return ev;
|
||||
}
|
||||
queue = queue->next;
|
||||
}
|
||||
|
||||
if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, *base)) {
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
|
||||
{
|
||||
struct fpm_event_queue_s *elt;
|
||||
|
||||
if (!queue || !ev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fpm_event_queue_isset(*queue, ev)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
|
||||
zlog(ZLOG_SYSERROR, "malloc() failed");
|
||||
return -1;
|
||||
}
|
||||
elt->prev = NULL;
|
||||
elt->next = NULL;
|
||||
elt->ev = ev;
|
||||
|
||||
if (*queue) {
|
||||
(*queue)->prev = elt;
|
||||
elt->next = *queue;
|
||||
}
|
||||
*queue = elt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
|
||||
{
|
||||
struct fpm_event_queue_s *q;
|
||||
if (!queue || !ev) {
|
||||
return -1;
|
||||
}
|
||||
q = *queue;
|
||||
while (q) {
|
||||
if (q->ev == ev) {
|
||||
if (q->prev) {
|
||||
q->prev->next = q->next;
|
||||
}
|
||||
if (q->next) {
|
||||
q->next->prev = q->prev;
|
||||
}
|
||||
if (q == *queue) {
|
||||
*queue = q->next;
|
||||
(*queue)->prev = NULL;
|
||||
}
|
||||
free(q);
|
||||
return 0;
|
||||
}
|
||||
q = q->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */
|
||||
{
|
||||
struct fpm_event_queue_s *q, *tmp;
|
||||
|
||||
if (!queue) {
|
||||
return;
|
||||
}
|
||||
q = *queue;
|
||||
while (q) {
|
||||
tmp = q;
|
||||
q = q->next;
|
||||
/* q->prev = NULL */
|
||||
free(tmp);
|
||||
}
|
||||
*queue = NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_event_init_main() /* {{{ */
|
||||
{
|
||||
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_loop(struct event_base *base) /* {{{ */
|
||||
void fpm_event_loop() /* {{{ */
|
||||
{
|
||||
static struct event signal_fd_event;
|
||||
static struct fpm_event_s signal_fd_event;
|
||||
|
||||
/* sanity check */
|
||||
if (fpm_globals.parent_pid != getpid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL);
|
||||
fpm_event_add(&signal_fd_event, 0);
|
||||
|
||||
/* add timers */
|
||||
fpm_pctl_heartbeat(NULL, 0, NULL);
|
||||
fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL);
|
||||
|
||||
event_set(&signal_fd_event, fpm_signals_get_fd(), EV_PERSIST | EV_READ, &fpm_got_signal, base);
|
||||
event_base_set(base, &signal_fd_event);
|
||||
event_add(&signal_fd_event, 0);
|
||||
fpm_pctl_heartbeat(-1, 0, base);
|
||||
fpm_pctl_perform_idle_server_maintenance_heartbeat(-1, 0, base);
|
||||
zlog(ZLOG_NOTICE, "ready to handle connections");
|
||||
event_base_dispatch(base);
|
||||
|
||||
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) /* {{{ */
|
||||
{
|
||||
if (!ev || !ev->callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
|
||||
{
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_event_add(int fd, struct event_base *base, struct event *ev, void (*callback)(int, short, void *), void *arg) /* {{{ */
|
||||
int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
|
||||
{
|
||||
event_set(ev, fd, EV_PERSIST | EV_READ, callback, arg);
|
||||
event_base_set(base, ev);
|
||||
return event_add(ev, 0);
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_event_del(struct event *ev) /* {{{ */
|
||||
int fpm_event_del(struct fpm_event_s *ev) /* {{{ */
|
||||
{
|
||||
return event_del(ev);
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void fpm_event_exit_loop(struct event_base *base) /* {{{ */
|
||||
{
|
||||
event_base_loopbreak(base);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void fpm_event_fire(struct event *ev) /* {{{ */
|
||||
{
|
||||
(*ev->ev_callback)( (int) ev->ev_fd, (short) ev->ev_res, ev->ev_arg);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -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
|
||||
|
@ -168,7 +168,6 @@ typedef struct _php_cgi_globals_struct {
|
||||
HashTable user_config_cache;
|
||||
char *error_header;
|
||||
char *fpm_config;
|
||||
struct event_base *event_base;
|
||||
} php_cgi_globals_struct;
|
||||
|
||||
/* {{{ user_config_cache
|
||||
@ -1780,11 +1779,11 @@ consult the installation file that came with this distribution, or visit \n\
|
||||
}
|
||||
}
|
||||
|
||||
if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, test_conf, &CGIG(event_base))) {
|
||||
if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, test_conf)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
fcgi_fd = fpm_run(&max_requests, CGIG(event_base));
|
||||
fcgi_fd = fpm_run(&max_requests);
|
||||
parent = 0;
|
||||
fcgi_set_is_fastcgi(1);
|
||||
|
||||
|
@ -49,29 +49,18 @@ static void fpm_pctl_cleanup(int which, void *arg) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static struct event pctl_event;
|
||||
static struct fpm_event_s pctl_event;
|
||||
|
||||
static void fpm_pctl_action(int fd, short which, void *arg) /* {{{ */
|
||||
static void fpm_pctl_action(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
|
||||
{
|
||||
struct event_base *base = (struct event_base *)arg;
|
||||
|
||||
evtimer_del(&pctl_event);
|
||||
memset(&pctl_event, 0, sizeof(pctl_event));
|
||||
fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int fpm_pctl_timeout_set(int sec, struct event_base *base) /* {{{ */
|
||||
static int fpm_pctl_timeout_set(int sec) /* {{{ */
|
||||
{
|
||||
struct timeval tv = { .tv_sec = sec, .tv_usec = 0 };
|
||||
|
||||
if (evtimer_initialized(&pctl_event)) {
|
||||
evtimer_del(&pctl_event);
|
||||
}
|
||||
|
||||
evtimer_set(&pctl_event, &fpm_pctl_action, base);
|
||||
event_base_set(base, &pctl_event);
|
||||
evtimer_add(&pctl_event, &tv);
|
||||
fpm_event_set_timer(&pctl_event, 0, &fpm_pctl_action, NULL);
|
||||
fpm_event_add(&pctl_event, sec * 1000);
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@ -181,7 +170,7 @@ static void fpm_pctl_kill_all(int signo) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void fpm_pctl_action_next(struct event_base *base) /* {{{ */
|
||||
static void fpm_pctl_action_next() /* {{{ */
|
||||
{
|
||||
int sig, timeout;
|
||||
|
||||
@ -207,11 +196,11 @@ static void fpm_pctl_action_next(struct event_base *base) /* {{{ */
|
||||
|
||||
fpm_pctl_kill_all(sig);
|
||||
fpm_signal_sent = sig;
|
||||
fpm_pctl_timeout_set(timeout, base);
|
||||
fpm_pctl_timeout_set(timeout);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void fpm_pctl(int new_state, int action, struct event_base *base) /* {{{ */
|
||||
void fpm_pctl(int new_state, int action) /* {{{ */
|
||||
{
|
||||
switch (action) {
|
||||
case FPM_PCTL_ACTION_SET :
|
||||
@ -243,7 +232,7 @@ void fpm_pctl(int new_state, int action, struct event_base *base) /* {{{ */
|
||||
/* fall down */
|
||||
|
||||
case FPM_PCTL_ACTION_TIMEOUT :
|
||||
fpm_pctl_action_next(base);
|
||||
fpm_pctl_action_next();
|
||||
break;
|
||||
case FPM_PCTL_ACTION_LAST_CHILD_EXITED :
|
||||
fpm_pctl_action_last();
|
||||
@ -259,14 +248,14 @@ int fpm_pctl_can_spawn_children() /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_pctl_child_exited(struct event_base *base) /* {{{ */
|
||||
int fpm_pctl_child_exited() /* {{{ */
|
||||
{
|
||||
if (fpm_state == FPM_PCTL_STATE_NORMAL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fpm_globals.running_children) {
|
||||
fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED, base);
|
||||
fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -318,7 +307,7 @@ static void fpm_pctl_check_request_timeout(struct timeval *now) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct event_base *base) /* {{{ */
|
||||
static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ */
|
||||
{
|
||||
struct fpm_worker_pool_s *wp;
|
||||
|
||||
@ -396,7 +385,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct
|
||||
}
|
||||
wp->warn_max_children = 0;
|
||||
|
||||
fpm_children_make(wp, 1, children_to_fork, 1, base);
|
||||
fpm_children_make(wp, 1, children_to_fork, 1);
|
||||
|
||||
/* if it's a child, stop here without creating the next event
|
||||
* this event is reserved to the master process
|
||||
@ -418,37 +407,40 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now, struct
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void fpm_pctl_heartbeat(int fd, short which, void *arg) /* {{{ */
|
||||
void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
|
||||
{
|
||||
static struct event heartbeat;
|
||||
struct timeval tv = { .tv_sec = 0, .tv_usec = 130000 };
|
||||
static struct fpm_event_s heartbeat;
|
||||
struct timeval now;
|
||||
struct event_base *base = (struct event_base *)arg;
|
||||
|
||||
if (which == EV_TIMEOUT) {
|
||||
evtimer_del(&heartbeat);
|
||||
fpm_clock_get(&now);
|
||||
fpm_pctl_check_request_timeout(&now);
|
||||
if (fpm_globals.parent_pid != getpid()) {
|
||||
return; /* sanity check */
|
||||
}
|
||||
|
||||
evtimer_set(&heartbeat, &fpm_pctl_heartbeat, base);
|
||||
event_base_set(base, &heartbeat);
|
||||
evtimer_add(&heartbeat, &tv);
|
||||
if (which == FPM_EV_TIMEOUT) {
|
||||
fpm_clock_get(&now);
|
||||
fpm_pctl_check_request_timeout(&now);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first call without setting to initialize the timer */
|
||||
fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_heartbeat, NULL);
|
||||
fpm_event_add(&heartbeat, FPM_PCTL_HEARTBEAT);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which, void *arg) /* {{{ */
|
||||
void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
|
||||
{
|
||||
static struct event heartbeat;
|
||||
struct timeval tv = { .tv_sec = 0, .tv_usec = FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT };
|
||||
static struct fpm_event_s heartbeat;
|
||||
struct timeval now;
|
||||
struct event_base *base = (struct event_base *)arg;
|
||||
|
||||
if (which == EV_TIMEOUT) {
|
||||
evtimer_del(&heartbeat);
|
||||
if (fpm_globals.parent_pid != getpid()) {
|
||||
return; /* sanity check */
|
||||
}
|
||||
|
||||
if (which == FPM_EV_TIMEOUT) {
|
||||
fpm_clock_get(&now);
|
||||
if (fpm_pctl_can_spawn_children()) {
|
||||
fpm_pctl_perform_idle_server_maintenance(&now, base);
|
||||
fpm_pctl_perform_idle_server_maintenance(&now);
|
||||
|
||||
/* if it's a child, stop here without creating the next event
|
||||
* this event is reserved to the master process
|
||||
@ -457,11 +449,12 @@ void fpm_pctl_perform_idle_server_maintenance_heartbeat(int fd, short which, voi
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
evtimer_set(&heartbeat, &fpm_pctl_perform_idle_server_maintenance_heartbeat, base);
|
||||
event_base_set(base, &heartbeat);
|
||||
evtimer_add(&heartbeat, &tv);
|
||||
/* first call without setting which to initialize the timer */
|
||||
fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_perform_idle_server_maintenance_heartbeat, NULL);
|
||||
fpm_event_add(&heartbeat, FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -71,18 +71,30 @@ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void fpm_stdio_child_said(int fd, short which, void *arg) /* {{{ */
|
||||
static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
|
||||
{
|
||||
static const int max_buf_size = 1024;
|
||||
int fd = ev->fd;
|
||||
char buf[max_buf_size];
|
||||
struct fpm_child_s *child = arg;
|
||||
int is_stdout = fd == child->fd_stdout;
|
||||
struct event *ev = is_stdout ? &child->ev_stdout : &child->ev_stderr;
|
||||
struct fpm_child_s *child;
|
||||
int is_stdout;
|
||||
struct fpm_event_s *event;
|
||||
int fifo_in = 1, fifo_out = 1;
|
||||
int is_last_message = 0;
|
||||
int in_buf = 0;
|
||||
int res;
|
||||
|
||||
if (!arg) {
|
||||
return;
|
||||
}
|
||||
child = (struct fpm_child_s *)arg;
|
||||
is_stdout = (fd == child->fd_stdout);
|
||||
if (is_stdout) {
|
||||
event = &child->ev_stdout;
|
||||
} else {
|
||||
event = &child->ev_stderr;
|
||||
}
|
||||
|
||||
while (fifo_in || fifo_out) {
|
||||
if (fifo_in) {
|
||||
res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf);
|
||||
@ -96,7 +108,7 @@ static void fpm_stdio_child_said(int fd, short which, void *arg) /* {{{ */
|
||||
zlog(ZLOG_SYSERROR, "read() failed");
|
||||
}
|
||||
|
||||
fpm_event_del(ev);
|
||||
fpm_event_del(event);
|
||||
is_last_message = 1;
|
||||
|
||||
if (is_stdout) {
|
||||
@ -183,7 +195,7 @@ int fpm_stdio_prepare_pipes(struct fpm_child_s *child) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int fpm_stdio_parent_use_pipes(struct fpm_child_s *child, struct event_base *base) /* {{{ */
|
||||
int fpm_stdio_parent_use_pipes(struct fpm_child_s *child) /* {{{ */
|
||||
{
|
||||
if (0 == child->wp->config->catch_workers_output) { /* not required */
|
||||
return 0;
|
||||
@ -195,8 +207,11 @@ int fpm_stdio_parent_use_pipes(struct fpm_child_s *child, struct event_base *bas
|
||||
child->fd_stdout = fd_stdout[0];
|
||||
child->fd_stderr = fd_stderr[0];
|
||||
|
||||
fpm_event_add(child->fd_stdout, base, &child->ev_stdout, fpm_stdio_child_said, child);
|
||||
fpm_event_add(child->fd_stderr, base, &child->ev_stderr, fpm_stdio_child_said, child);
|
||||
fpm_event_set(&child->ev_stdout, child->fd_stdout, FPM_EV_READ, fpm_stdio_child_said, child);
|
||||
fpm_event_add(&child->ev_stdout, 0);
|
||||
|
||||
fpm_event_set(&child->ev_stderr, child->fd_stderr, FPM_EV_READ, fpm_stdio_child_said, child);
|
||||
fpm_event_add(&child->ev_stderr, 0);
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -268,6 +268,8 @@ pm.max_children = 50
|
||||
|
||||
; Redirect worker stdout and stderr into main error log. If not set, stdout and
|
||||
; stderr will be redirected to /dev/null according to FastCGI specs.
|
||||
; Note: on highloaded environement, this can cause some delay in the page
|
||||
; process time (several ms).
|
||||
; Default Value: no
|
||||
;catch_workers_output = yes
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user