. Fixed bug #53872 (internal corruption of phar). (Hannes)
- PHP-FPM SAPI:
+ . Implemented FR #52569 (Add the "ondemand" process-manager
+ to allow zero children). (fat)
. Fixed bug #55486 (status show BIG processes number). (fat)
. Fixed bug #55577 (status.html does not install). (fat)
. Backported from 5.4 branch (Dropped restriction of not setting the same
$(builddir)/fpm:
@mkdir -p $(builddir)/fpm
+ @mkdir -p $(builddir)/fpm/events
$(SAPI_FPM_PATH): $(builddir)/fpm $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(SAPI_EXTRA_DEPS)
$(BUILD_FPM)
])
dnl }}}
+AC_DEFUN([AC_FPM_KQUEUE],
+[
+ AC_MSG_CHECKING([for kqueue])
+
+ AC_TRY_COMPILE(
+ [
+ #include <sys/types.h>
+ #include <sys/event.h>
+ #include <sys/time.h>
+ ], [
+ int kfd;
+ struct kevent k;
+ kfd = kqueue();
+ /* 0 -> STDIN_FILENO */
+ EV_SET(&k, 0, EVFILT_READ , EV_ADD | EV_CLEAR, 0, 0, NULL);
+ ], [
+ AC_DEFINE([HAVE_KQUEUE], 1, [do we have kqueue?])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+dnl }}}
+
+AC_DEFUN([AC_FPM_PORT],
+[
+ AC_MSG_CHECKING([for port framework])
+
+ AC_TRY_COMPILE(
+ [
+ #include <port.h>
+ ], [
+ int port;
+
+ port = port_create();
+ if (port < 0) {
+ return 1;
+ }
+ ], [
+ AC_DEFINE([HAVE_PORT], 1, [do we have port framework?])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+dnl }}}
+
+AC_DEFUN([AC_FPM_DEVPOLL],
+[
+ AC_MSG_CHECKING([for /dev/poll])
+
+ AC_TRY_COMPILE(
+ [
+ #include <stdio.h>
+ #include <sys/devpoll.h>
+ ], [
+ int n, dp;
+ struct dvpoll dvp;
+ dp = 0;
+ dvp.dp_fds = NULL;
+ dvp.dp_nfds = 0;
+ dvp.dp_timeout = 0;
+ n = ioctl(dp, DP_POLL, &dvp)
+ ], [
+ AC_DEFINE([HAVE_DEVPOLL], 1, [do we have /dev/poll?])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+dnl }}}
+
+AC_DEFUN([AC_FPM_EPOLL],
+[
+ AC_MSG_CHECKING([for epoll])
+
+ AC_TRY_COMPILE(
+ [
+ #include <sys/epoll.h>
+ ], [
+ int epollfd;
+ struct epoll_event e;
+
+ epollfd = epoll_create(1);
+ if (epollfd < 0) {
+ return 1;
+ }
+
+ e.events = EPOLLIN | EPOLLET;
+ e.data.fd = 0;
+
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, 0, &e) == -1) {
+ return 1;
+ }
+
+ e.events = 0;
+ if (epoll_wait(epollfd, &e, 1, 1) < 0) {
+ return 1;
+ }
+ ], [
+ AC_DEFINE([HAVE_EPOLL], 1, [do we have epoll?])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+dnl }}}
+
+AC_DEFUN([AC_FPM_POLL],
+[
+ AC_MSG_CHECKING([for poll])
+
+ AC_TRY_COMPILE(
+ [
+ #include <poll.h>
+ ], [
+ struct pollfd fds[2];
+
+ fds[0].fd = 0;
+ fds[0].events = POLLIN;
+
+ fds[1].fd = 0;
+ fds[1].events = POLLIN;
+
+ poll(fds, 2, 1);
+ ], [
+ AC_DEFINE([HAVE_POLL], 1, [do we have poll?])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+dnl }}}
+
+AC_DEFUN([AC_FPM_SELECT],
+[
+ AC_MSG_CHECKING([for select])
+
+ AC_TRY_COMPILE(
+ [
+ /* According to POSIX.1-2001 */
+ #include <sys/select.h>
+
+ /* According to earlier standards */
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <unistd.h>
+ ], [
+ fd_set fds;
+ struct timeval t;
+ t.tv_sec = 0;
+ t.tv_usec = 42;
+ FD_ZERO(&fds);
+ /* 0 -> STDIN_FILENO */
+ FD_SET(0, &fds);
+ select(FD_SETSIZE, &fds, NULL, NULL, &t);
+ ], [
+ AC_DEFINE([HAVE_SELECT], 1, [do we have select?])
+ AC_MSG_RESULT([yes])
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+])
+dnl }}}
+
AC_MSG_CHECKING(for FPM build)
if test "$PHP_FPM" != "no"; then
AC_FPM_LQ
AC_FPM_SYSCONF
AC_FPM_TIMES
+ AC_FPM_KQUEUE
+ AC_FPM_PORT
+ AC_FPM_DEVPOLL
+ AC_FPM_EPOLL
+ AC_FPM_POLL
+ AC_FPM_SELECT
PHP_ARG_WITH(fpm-user,,
[ --with-fpm-user[=USER] Set the user for php-fpm to run as. (default: nobody)], nobody, no)
fpm/fpm_unix.c \
fpm/fpm_worker_pool.c \
fpm/zlog.c \
+ fpm/events/select.c \
+ fpm/events/poll.c \
+ fpm/events/epoll.c \
+ fpm/events/kqueue.c \
+ fpm/events/devpoll.c \
+ fpm/events/port.c \
"
PHP_SELECT_SAPI(fpm, program, $PHP_FPM_FILES $PHP_FPM_TRACE_FILES, $PHP_FPM_CFLAGS, '$(SAPI_FPM_PATH)')
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+#include "../fpm.h"
+#include "../zlog.h"
+
+#if HAVE_DEVPOLL
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/devpoll.h>
+#include <errno.h>
+
+static int fpm_event_devpoll_init(int max);
+static int fpm_event_devpoll_clean();
+static int fpm_event_devpoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
+static int fpm_event_devpoll_add(struct fpm_event_s *ev);
+static int fpm_event_devpoll_remove(struct fpm_event_s *ev);
+
+static struct fpm_event_module_s devpoll_module = {
+ .name = "/dev/poll",
+ .support_edge_trigger = 0,
+ .init = fpm_event_devpoll_init,
+ .clean = fpm_event_devpoll_clean,
+ .wait = fpm_event_devpoll_wait,
+ .add = fpm_event_devpoll_add,
+ .remove = fpm_event_devpoll_remove,
+};
+
+int dpfd = -1;
+static struct pollfd *pollfds = NULL;
+static struct pollfd *active_pollfds = NULL;
+static int npollfds = 0;
+
+#endif /* HAVE_DEVPOLL */
+
+struct fpm_event_module_s *fpm_event_devpoll_module() /* {{{ */
+{
+#if HAVE_DEVPOLL
+ return &devpoll_module;
+#else
+ return NULL;
+#endif /* HAVE_DEVPOLL */
+}
+/* }}} */
+
+#if HAVE_DEVPOLL
+
+/*
+ * Init module
+ */
+static int fpm_event_devpoll_init(int max) /* {{{ */
+{
+ int i;
+
+ /* open /dev/poll for future usages */
+ dpfd = open("/dev/poll", O_RDWR);
+ if (dpfd < 0) {
+ zlog(ZLOG_ERROR, "Unable to open /dev/poll");
+ return -1;
+ }
+
+ if (max < 1) {
+ return 0;
+ }
+
+ /* alloc and clear pollfds */
+ pollfds = malloc(sizeof(struct pollfd) * max);
+ if (!pollfds) {
+ zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
+ return -1;
+ }
+ memset(pollfds, 0, sizeof(struct pollfd) * max);
+
+ /* set all fd to -1 in order to ensure it's not set */
+ for (i = 0; i < max; i++) {
+ pollfds[i].fd = -1;
+ }
+
+ /* alloc and clear active_pollfds */
+ active_pollfds = malloc(sizeof(struct pollfd) * max);
+ if (!active_pollfds) {
+ free(pollfds);
+ zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
+ return -1;
+ }
+ memset(active_pollfds, 0, sizeof(struct pollfd) * max);
+
+ /* save max */
+ npollfds = max;
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * Clean the module
+ */
+static int fpm_event_devpoll_clean() /* {{{ */
+{
+ /* close /dev/poll if open */
+ if (dpfd > -1) {
+ close(dpfd);
+ dpfd = -1;
+ }
+
+ /* free pollfds */
+ if (pollfds) {
+ free(pollfds);
+ pollfds = NULL;
+ }
+
+ /* free active_pollfds */
+ if (active_pollfds) {
+ free(active_pollfds);
+ active_pollfds = NULL;
+ }
+
+ npollfds = 0;
+ return 0;
+}
+/* }}} */
+
+/*
+ * wait for events or timeout
+ */
+static int fpm_event_devpoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
+{
+ int ret, i;
+ struct fpm_event_queue_s *q;
+ struct dvpoll dopoll;
+
+ /* setup /dev/poll */
+ dopoll.dp_fds = active_pollfds;
+ dopoll.dp_nfds = npollfds;
+ dopoll.dp_timeout = (int)timeout;
+
+ /* wait for inconming event or timeout */
+ ret = ioctl(dpfd, DP_POLL, &dopoll);
+
+ if (ret < 0) {
+
+ /* trigger error unless signal interrupt */
+ if (errno != EINTR) {
+ zlog(ZLOG_WARNING, "/dev/poll: ioctl() returns %d", errno);
+ return -1;
+ }
+ }
+
+ /* iterate throught triggered events */
+ for (i = 0; i < ret; i++) {
+
+ /* find the corresponding event */
+ q = queue;
+ while (q) {
+
+ /* found */
+ if (q->ev && q->ev->fd == active_pollfds[i].fd) {
+
+ /* fire the event */
+ fpm_event_fire(q->ev);
+
+ /* sanity check */
+ if (fpm_globals.parent_pid != getpid()) {
+ return -2;
+ }
+ break; /* next triggered event */
+ }
+ q = q->next; /* iterate */
+ }
+ }
+
+ return ret;
+}
+/* }}} */
+
+/*
+ * Add a FD from the fd set
+ */
+static int fpm_event_devpoll_add(struct fpm_event_s *ev) /* {{{ */
+{
+ struct pollfd pollfd;
+
+ /* fill pollfd with event informations */
+ pollfd.fd = ev->fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+
+ /* add the event to the internal queue */
+ if (write(dpfd, &pollfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) {
+ zlog(ZLOG_ERROR, "/dev/poll: Unable to add the event in the internal queue");
+ return -1;
+ }
+
+ /* mark the event as registered */
+ ev->index = ev->fd;
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * Remove a FD from the fd set
+ */
+static int fpm_event_devpoll_remove(struct fpm_event_s *ev) /* {{{ */
+{
+ struct pollfd pollfd;
+
+ /* fill pollfd with the same informations as fpm_event_devpoll_add */
+ pollfd.fd = ev->fd;
+ pollfd.events = POLLIN | POLLREMOVE;
+ pollfd.revents = 0;
+
+ /* add the event to the internal queue */
+ if (write(dpfd, &pollfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) {
+ zlog(ZLOG_ERROR, "/dev/poll: Unable to remove the event in the internal queue");
+ return -1;
+ }
+
+ /* mark the event as registered */
+ ev->index = -1;
+
+ return 0;
+}
+/* }}} */
+
+#endif /* HAVE_DEVPOLL */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef FPM_EVENTS_DEVPOLL_H
+#define FPM_EVENTS_DEVPOLL_H
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+
+struct fpm_event_module_s *fpm_event_devpoll_module();
+
+#endif /* FPM_EVENTS_DEVPOLL_H */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+#include "../fpm.h"
+#include "../zlog.h"
+
+#if HAVE_EPOLL
+
+#include <sys/epoll.h>
+#include <errno.h>
+
+static int fpm_event_epoll_init(int max);
+static int fpm_event_epoll_clean();
+static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
+static int fpm_event_epoll_add(struct fpm_event_s *ev);
+static int fpm_event_epoll_remove(struct fpm_event_s *ev);
+
+static struct fpm_event_module_s epoll_module = {
+ .name = "epoll",
+ .support_edge_trigger = 1,
+ .init = fpm_event_epoll_init,
+ .clean = fpm_event_epoll_clean,
+ .wait = fpm_event_epoll_wait,
+ .add = fpm_event_epoll_add,
+ .remove = fpm_event_epoll_remove,
+};
+
+static struct epoll_event *epollfds = NULL;
+static int nepollfds = 0;
+static int epollfd = 0;
+
+#endif /* HAVE_EPOLL */
+
+struct fpm_event_module_s *fpm_event_epoll_module() /* {{{ */
+{
+#if HAVE_EPOLL
+ return &epoll_module;
+#else
+ return NULL;
+#endif /* HAVE_EPOLL */
+}
+/* }}} */
+
+#if HAVE_EPOLL
+
+/*
+ * Init the module
+ */
+static int fpm_event_epoll_init(int max) /* {{{ */
+{
+ if (max < 1) {
+ return 0;
+ }
+
+ /* init epoll */
+ epollfd = epoll_create(max + 1);
+ if (epollfd < 0) {
+ zlog(ZLOG_ERROR, "epoll: unable to initialize");
+ return -1;
+ }
+
+ /* allocate fds */
+ epollfds = malloc(sizeof(struct epoll_event) * max);
+ if (!epollfds) {
+ zlog(ZLOG_ERROR, "epoll: unable to allocate %d events", max);
+ return -1;
+ }
+ memset(epollfds, 0, sizeof(struct epoll_event) * max);
+
+ /* save max */
+ nepollfds = max;
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * Clean the module
+ */
+static int fpm_event_epoll_clean() /* {{{ */
+{
+ /* free epollfds */
+ if (epollfds) {
+ free(epollfds);
+ epollfds = NULL;
+ }
+
+ nepollfds = 0;
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * wait for events or timeout
+ */
+static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
+{
+ int ret, i;
+
+ /* ensure we have a clean epoolfds before calling epoll_wait() */
+ memset(epollfds, 0, sizeof(struct epoll_event) * nepollfds);
+
+ /* wait for inconming event or timeout */
+ ret = epoll_wait(epollfd, epollfds, nepollfds, timeout);
+ if (ret == -1) {
+
+ /* trigger error unless signal interrupt */
+ if (errno != EINTR) {
+ zlog(ZLOG_WARNING, "epoll_wait() returns %d", errno);
+ return -1;
+ }
+ }
+
+ /* events have been triggered, let's fire them */
+ for (i = 0; i < ret; i++) {
+
+ /* do we have a valid ev ptr ? */
+ if (!epollfds[i].data.ptr) {
+ continue;
+ }
+
+ /* fire the event */
+ fpm_event_fire((struct fpm_event_s *)epollfds[i].data.ptr);
+
+ /* sanity check */
+ if (fpm_globals.parent_pid != getpid()) {
+ return -2;
+ }
+ }
+
+ return ret;
+}
+/* }}} */
+
+/*
+ * Add a FD to the fd set
+ */
+static int fpm_event_epoll_add(struct fpm_event_s *ev) /* {{{ */
+{
+ struct epoll_event e;
+
+ /* fill epoll struct */
+ e.events = EPOLLIN;
+ e.data.fd = ev->fd;
+ e.data.ptr = (void *)ev;
+
+ if (ev->flags & FPM_EV_EDGE) {
+ e.events = e.events | EPOLLET;
+ }
+
+ /* add the event to epoll internal queue */
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ev->fd, &e) == -1) {
+ zlog(ZLOG_ERROR, "epoll: unable to add fd %d", ev->fd);
+ return -1;
+ }
+
+ /* mark the event as registered */
+ ev->index = ev->fd;
+ return 0;
+}
+/* }}} */
+
+/*
+ * Remove a FD from the fd set
+ */
+static int fpm_event_epoll_remove(struct fpm_event_s *ev) /* {{{ */
+{
+ struct epoll_event e;
+
+ /* fill epoll struct the same way we did in fpm_event_epoll_add() */
+ e.events = EPOLLIN;
+ e.data.fd = ev->fd;
+ e.data.ptr = (void *)ev;
+
+ if (ev->flags & FPM_EV_EDGE) {
+ e.events = e.events | EPOLLET;
+ }
+
+ /* remove the event from epoll internal queue */
+ if (epoll_ctl(epollfd, EPOLL_CTL_DEL, ev->fd, &e) == -1) {
+ zlog(ZLOG_ERROR, "epoll: unable to remove fd %d", ev->fd);
+ return -1;
+ }
+
+ /* mark the event as not registered */
+ ev->index = -1;
+ return 0;
+}
+/* }}} */
+
+#endif /* HAVE_EPOLL */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef FPM_EVENTS_EPOLL_H
+#define FPM_EVENTS_EPOLL_H
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+
+struct fpm_event_module_s *fpm_event_epoll_module();
+
+#endif /* FPM_EVENTS_EPOLL_H */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+#include "../fpm.h"
+#include "../zlog.h"
+
+#if HAVE_KQUEUE
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+#include <errno.h>
+
+static int fpm_event_kqueue_init(int max);
+static int fpm_event_kqueue_clean();
+static int fpm_event_kqueue_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
+static int fpm_event_kqueue_add(struct fpm_event_s *ev);
+static int fpm_event_kqueue_remove(struct fpm_event_s *ev);
+
+static struct fpm_event_module_s kqueue_module = {
+ .name = "kqueue",
+ .support_edge_trigger = 1,
+ .init = fpm_event_kqueue_init,
+ .clean = fpm_event_kqueue_clean,
+ .wait = fpm_event_kqueue_wait,
+ .add = fpm_event_kqueue_add,
+ .remove = fpm_event_kqueue_remove,
+};
+
+static struct kevent *kevents = NULL;
+static int nkevents = 0;
+static int kfd = 0;
+
+#endif /* HAVE_KQUEUE */
+
+/*
+ * Return the module configuration
+ */
+struct fpm_event_module_s *fpm_event_kqueue_module() /* {{{ */
+{
+#if HAVE_KQUEUE
+ return &kqueue_module;
+#else
+ return NULL;
+#endif /* HAVE_KQUEUE */
+}
+/* }}} */
+
+#if HAVE_KQUEUE
+
+/*
+ * init kqueue and stuff
+ */
+static int fpm_event_kqueue_init(int max) /* {{{ */
+{
+ if (max < 1) {
+ return 0;
+ }
+
+ kfd = kqueue();
+ if (kfd < 0) {
+ zlog(ZLOG_ERROR, "kqueue: unable to initialize");
+ return -1;
+ }
+
+ kevents = malloc(sizeof(struct kevent) * max);
+ if (!kevents) {
+ zlog(ZLOG_ERROR, "epoll: unable to allocate %d events", max);
+ return -1;
+ }
+
+ memset(kevents, 0, sizeof(struct kevent) * max);
+
+ nkevents = max;
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * release kqueue stuff
+ */
+static int fpm_event_kqueue_clean() /* {{{ */
+{
+ if (kevents) {
+ free(kevents);
+ kevents = NULL;
+ }
+
+ nkevents = 0;
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * wait for events or timeout
+ */
+static int fpm_event_kqueue_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
+{
+ struct timespec t;
+ int ret, i;
+
+ /* ensure we have a clean kevents before calling kevent() */
+ memset(kevents, 0, sizeof(struct kevent) * nkevents);
+
+ /* convert ms to timespec struct */
+ t.tv_sec = timeout / 1000;
+ t.tv_nsec = (timeout % 1000) * 1000 * 1000;
+
+ /* wait for incoming event or timeout */
+ ret = kevent(kfd, NULL, 0, kevents, nkevents, &t);
+ if (ret == -1) {
+
+ /* trigger error unless signal interrupt */
+ if (errno != EINTR) {
+ zlog(ZLOG_WARNING, "epoll_wait() returns %d", errno);
+ return -1;
+ }
+ }
+
+ /* fire triggered events */
+ for (i = 0; i < ret; i++) {
+ if (kevents[i].udata) {
+ struct fpm_event_s *ev = (struct fpm_event_s *)kevents[i].udata;
+ fpm_event_fire(ev);
+ /* sanity check */
+ if (fpm_globals.parent_pid != getpid()) {
+ return -2;
+ }
+ }
+ }
+
+ return ret;
+}
+/* }}} */
+
+/*
+ * Add a FD to to kevent queue
+ */
+static int fpm_event_kqueue_add(struct fpm_event_s *ev) /* {{{ */
+{
+ struct kevent k;
+ int flags = EV_ADD;
+
+ if (ev->flags & FPM_EV_EDGE) {
+ flags = flags | EV_CLEAR;
+ }
+
+ EV_SET(&k, ev->fd, EVFILT_READ, flags, 0, 0, (void *)ev);
+
+ if (kevent(kfd, &k, 1, NULL, 0, NULL) < 0) {
+ zlog(ZLOG_ERROR, "kevent: unable to add event");
+ return -1;
+ }
+
+ /* mark the event as registered */
+ ev->index = ev->fd;
+ return 0;
+}
+/* }}} */
+
+/*
+ * Remove a FD from the kevent queue
+ */
+static int fpm_event_kqueue_remove(struct fpm_event_s *ev) /* {{{ */
+{
+ struct kevent k;
+ int flags = EV_DELETE;
+
+ if (ev->flags & FPM_EV_EDGE) {
+ flags = flags | EV_CLEAR;
+ }
+
+ EV_SET(&k, ev->fd, EVFILT_READ, flags, 0, 0, (void *)ev);
+
+ if (kevent(kfd, &k, 1, NULL, 0, NULL) < 0) {
+ zlog(ZLOG_ERROR, "kevent: unable to add event");
+ return -1;
+ }
+
+ /* mark the vent as not registered */
+ ev->index = -1;
+ return 0;
+}
+/* }}} */
+
+#endif /* HAVE_KQUEUE */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef FPM_EVENTS_KQUEUE_H
+#define FPM_EVENTS_KQUEUE_H
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+
+struct fpm_event_module_s *fpm_event_kqueue_module();
+
+#endif /* FPM_EVENTS_KQUEUE_H */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+#include "../fpm.h"
+#include "../zlog.h"
+
+#if HAVE_POLL
+
+#include <poll.h>
+#include <errno.h>
+#include <string.h>
+
+static int fpm_event_poll_init(int max);
+static int fpm_event_poll_clean();
+static int fpm_event_poll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
+static int fpm_event_poll_add(struct fpm_event_s *ev);
+static int fpm_event_poll_remove(struct fpm_event_s *ev);
+
+static struct fpm_event_module_s poll_module = {
+ .name = "poll",
+ .support_edge_trigger = 0,
+ .init = fpm_event_poll_init,
+ .clean = fpm_event_poll_clean,
+ .wait = fpm_event_poll_wait,
+ .add = fpm_event_poll_add,
+ .remove = fpm_event_poll_remove,
+};
+
+static struct pollfd *pollfds = NULL;
+static struct pollfd *active_pollfds = NULL;
+static int npollfds = 0;
+static int next_free_slot = 0;
+#endif /* HAVE_POLL */
+
+/*
+ * return the module configuration
+ */
+struct fpm_event_module_s *fpm_event_poll_module() /* {{{ */
+{
+#if HAVE_POLL
+ return &poll_module;
+#else
+ return NULL;
+#endif /* HAVE_POLL */
+}
+/* }}} */
+
+#if HAVE_POLL
+
+/*
+ * Init the module
+ */
+static int fpm_event_poll_init(int max) /* {{{ */
+{
+ int i;
+
+ if (max < 1) {
+ return 0;
+ }
+
+ /* alloc and clear pollfds */
+ pollfds = malloc(sizeof(struct pollfd) * max);
+ if (!pollfds) {
+ zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
+ return -1;
+ }
+ memset(pollfds, 0, sizeof(struct pollfd) * max);
+
+ /* set all fd to -1 in order to ensure it's not set */
+ for (i = 0; i < max; i++) {
+ pollfds[i].fd = -1;
+ }
+
+ /* alloc and clear active_pollfds */
+ active_pollfds = malloc(sizeof(struct pollfd) * max);
+ if (!active_pollfds) {
+ free(pollfds);
+ zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
+ return -1;
+ }
+ memset(active_pollfds, 0, sizeof(struct pollfd) * max);
+
+ /* save max */
+ npollfds = max;
+ return 0;
+}
+/* }}} */
+
+/*
+ * Clean the module
+ */
+static int fpm_event_poll_clean() /* {{{ */
+{
+ /* free pollfds */
+ if (pollfds) {
+ free(pollfds);
+ pollfds = NULL;
+ }
+
+ /* free active_pollfds */
+ if (active_pollfds) {
+ free(active_pollfds);
+ active_pollfds = NULL;
+ }
+
+ npollfds = 0;
+ return 0;
+}
+/* }}} */
+
+/*
+ * wait for events or timeout
+ */
+static int fpm_event_poll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
+{
+ int ret;
+ struct fpm_event_queue_s *q;
+
+ if (npollfds > 0) {
+ /* copy pollfds because poll() alters it */
+ memcpy(active_pollfds, pollfds, sizeof(struct pollfd) * npollfds);
+ }
+
+ /* wait for inconming event or timeout */
+ ret = poll(active_pollfds, npollfds, timeout);
+ if (ret == -1) {
+
+ /* trigger error unless signal interrupt */
+ if (errno != EINTR) {
+ zlog(ZLOG_WARNING, "poll() returns %d", errno);
+ return -1;
+ }
+ }
+
+ /* events have been triggered */
+ if (ret > 0) {
+
+ /* trigger POLLIN events */
+ q = queue;
+ while (q) {
+ /* ensure ev->index is valid */
+ if (q->ev && q->ev->index >= 0 && q->ev->index < npollfds && q->ev->fd == active_pollfds[q->ev->index].fd) {
+
+ /* has the event has been triggered ? */
+ if (active_pollfds[q->ev->index].revents & POLLIN) {
+
+ /* fire the event */
+ fpm_event_fire(q->ev);
+
+ /* sanity check */
+ if (fpm_globals.parent_pid != getpid()) {
+ return -2;
+ }
+ }
+ }
+ q = q->next; /* iterate */
+ }
+ }
+
+ return ret;
+}
+/* }}} */
+
+/*
+ * Add a FD to the fd set
+ */
+static int fpm_event_poll_add(struct fpm_event_s *ev) /* {{{ */
+{
+ int i;
+
+ /* do we have a direct free slot */
+ if (pollfds[next_free_slot].fd == -1) {
+ /* register the event */
+ pollfds[next_free_slot].fd = ev->fd;
+ pollfds[next_free_slot].events = POLLIN;
+
+ /* remember the event place in the fd list and suppose next slot is free */
+ ev->index = next_free_slot++;
+ if (next_free_slot >= npollfds) {
+ next_free_slot = 0;
+ }
+ return 0;
+ }
+
+ /* let's search */
+ for (i = 0; i < npollfds; i++) {
+ if (pollfds[i].fd != -1) {
+ /* not free */
+ continue;
+ }
+
+ /* register the event */
+ pollfds[i].fd = ev->fd;
+ pollfds[i].events = POLLIN;
+
+ /* remember the event place in the fd list and suppose next slot is free */
+ ev->index = next_free_slot++;
+ if (next_free_slot >= npollfds) {
+ next_free_slot = 0;
+ }
+ return 0;
+ }
+
+ zlog(ZLOG_ERROR, "poll: not enought space to add event (fd=%d)", ev->fd);
+ return -1;
+}
+/* }}} */
+
+/*
+ * Remove a FD from the fd set
+ */
+static int fpm_event_poll_remove(struct fpm_event_s *ev) /* {{{ */
+{
+ int i;
+
+ /* do we have a direct access */
+ if (ev->index >= 0 && ev->index < npollfds && pollfds[ev->index].fd == ev->fd) {
+ /* remember this slot as free */
+ next_free_slot = ev->index;
+
+ /* clear event in pollfds */
+ pollfds[ev->index].fd = -1;
+ pollfds[ev->index].events = 0;
+
+ /* mark the event as not registered */
+ ev->index = -1;
+
+ return 0;
+ }
+
+ /* let's search */
+ for (i = 0; i < npollfds; i++) {
+
+ if (pollfds[i].fd != ev->fd) {
+ /* not found */
+ continue;
+ }
+
+ /* remember this slot as free */
+ next_free_slot = i;
+
+ /* clear event in pollfds */
+ pollfds[i].fd = -1;
+ pollfds[i].events = 0;
+
+ /* mark the event as not registered */
+ ev->index = -1;
+
+ return 0;
+ }
+
+ zlog(ZLOG_ERROR, "poll: unable to remove event: not found (fd=%d, index=%d)", ev->fd, ev->index);
+ return -1;
+}
+/* }}} */
+
+#endif /* HAVE_POLL */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef FPM_EVENTS_POLL_H
+#define FPM_EVENTS_POLL_H
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+
+struct fpm_event_module_s *fpm_event_poll_module();
+
+#endif /* FPM_EVENTS_POLL_H */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+#include "../fpm.h"
+#include "../zlog.h"
+
+#if HAVE_PORT
+
+#include <port.h>
+#include <poll.h>
+#include <errno.h>
+
+static int fpm_event_port_init(int max);
+static int fpm_event_port_clean();
+static int fpm_event_port_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
+static int fpm_event_port_add(struct fpm_event_s *ev);
+static int fpm_event_port_remove(struct fpm_event_s *ev);
+
+static struct fpm_event_module_s port_module = {
+ .name = "port",
+ .support_edge_trigger = 0,
+ .init = fpm_event_port_init,
+ .clean = fpm_event_port_clean,
+ .wait = fpm_event_port_wait,
+ .add = fpm_event_port_add,
+ .remove = fpm_event_port_remove,
+};
+
+port_event_t *events = NULL;
+int nevents = 0;
+static int pfd = -1;
+
+#endif /* HAVE_PORT */
+
+struct fpm_event_module_s *fpm_event_port_module() /* {{{ */
+{
+#if HAVE_PORT
+ return &port_module;
+#else
+ return NULL;
+#endif /* HAVE_PORT */
+}
+/* }}} */
+
+#if HAVE_PORT
+
+/*
+ * Init the module
+ */
+static int fpm_event_port_init(int max) /* {{{ */
+{
+ /* open port */
+ pfd = port_create();
+ if (pfd < 0) {
+ zlog(ZLOG_ERROR, "port: unable to initialize port_create()");
+ return -1;
+ }
+
+ if (max < 1) {
+ return 0;
+ }
+
+ /* alloc and clear active_pollfds */
+ events = malloc(sizeof(port_event_t) * max);
+ if (!events) {
+ zlog(ZLOG_ERROR, "port: Unable to allocate %d events", max);
+ return -1;
+ }
+
+ nevents = max;
+ return 0;
+}
+/* }}} */
+
+/*
+ * Clean the module
+ */
+static int fpm_event_port_clean() /* {{{ */
+{
+ if (pfd > -1) {
+ close(pfd);
+ pfd = -1;
+ }
+
+ if (events) {
+ free(events);
+ events = NULL;
+ }
+
+ nevents = 0;
+ return 0;
+}
+/* }}} */
+
+/*
+ * wait for events or timeout
+ */
+static int fpm_event_port_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
+{
+ int ret, i, nget;
+ timespec_t t;
+
+ /* convert timeout into timespec_t */
+ t.tv_sec = (int)(timeout / 1000);
+ t.tv_nsec = (timeout % 1000) * 1000 * 1000;
+
+ /* wait for inconming event or timeout. We want at least one event or timeout */
+ nget = 1;
+ ret = port_getn(pfd, events, nevents, &nget, &t);
+ if (ret < 0) {
+
+ /* trigger error unless signal interrupt or timeout */
+ if (errno != EINTR && errno != ETIME) {
+ zlog(ZLOG_WARNING, "poll() returns %d", errno);
+ return -1;
+ }
+ }
+
+ for (i = 0; i < nget; i++) {
+
+ /* do we have a ptr to the event ? */
+ if (!events[i].portev_user) {
+ continue;
+ }
+
+ /* fire the event */
+ fpm_event_fire((struct fpm_event_s *)events[i].portev_user);
+
+ /* sanity check */
+ if (fpm_globals.parent_pid != getpid()) {
+ return -2;
+ }
+ }
+ return nget;
+}
+/* }}} */
+
+/*
+ * Add a FD to the fd set
+ */
+static int fpm_event_port_add(struct fpm_event_s *ev) /* {{{ */
+{
+ /* add the event to port */
+ if (port_associate(pfd, PORT_SOURCE_FD, ev->fd, POLLIN, (void *)ev) < 0) {
+ zlog(ZLOG_ERROR, "port: unable to add the event");
+ return -1;
+ }
+ return 0;
+}
+/* }}} */
+
+/*
+ * Remove a FD from the fd set
+ */
+static int fpm_event_port_remove(struct fpm_event_s *ev) /* {{{ */
+{
+ /* remove the event from port */
+ if (port_dissociate(pfd, PORT_SOURCE_FD, ev->fd) < 0) {
+ zlog(ZLOG_ERROR, "port: unable to add the event");
+ return -1;
+ }
+ return 0;
+}
+/* }}} */
+
+#endif /* HAVE_PORT */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef FPM_EVENTS_PORT_H
+#define FPM_EVENTS_PORT_H
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+
+struct fpm_event_module_s *fpm_event_port_module();
+
+#endif /* FPM_EVENTS_PORT_H */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+#include "../fpm.h"
+#include "../zlog.h"
+
+#if HAVE_SELECT
+
+/* According to POSIX.1-2001 */
+#include <sys/select.h>
+
+/* According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+static int fpm_event_select_init(int max);
+static int fpm_event_select_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
+static int fpm_event_select_add(struct fpm_event_s *ev);
+static int fpm_event_select_remove(struct fpm_event_s *ev);
+
+static struct fpm_event_module_s select_module = {
+ .name = "select",
+ .support_edge_trigger = 0,
+ .init = fpm_event_select_init,
+ .clean = NULL,
+ .wait = fpm_event_select_wait,
+ .add = fpm_event_select_add,
+ .remove = fpm_event_select_remove,
+};
+
+static fd_set fds;
+
+#endif /* HAVE_SELECT */
+
+/*
+ * return the module configuration
+ */
+struct fpm_event_module_s *fpm_event_select_module() /* {{{ */
+{
+#if HAVE_SELECT
+ return &select_module;
+#else
+ return NULL;
+#endif /* HAVE_SELECT */
+}
+/* }}} */
+
+#if HAVE_SELECT
+
+/*
+ * Init the module
+ */
+static int fpm_event_select_init(int max) /* {{{ */
+{
+ FD_ZERO(&fds);
+ return 0;
+}
+/* }}} */
+
+
+/*
+ * wait for events or timeout
+ */
+static int fpm_event_select_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
+{
+ int ret;
+ struct fpm_event_queue_s *q;
+ fd_set current_fds;
+ struct timeval t;
+
+ /* copy fds because select() alters it */
+ current_fds = fds;
+
+ /* fill struct timeval with timeout */
+ t.tv_sec = timeout / 1000;
+ t.tv_usec = (timeout % 1000) * 1000;
+
+ /* wait for inconming event or timeout */
+ ret = select(FD_SETSIZE, ¤t_fds, NULL, NULL, &t);
+ if (ret == -1) {
+
+ /* trigger error unless signal interrupt */
+ if (errno != EINTR) {
+ zlog(ZLOG_WARNING, "poll() returns %d", errno);
+ return -1;
+ }
+ }
+
+ /* events have been triggered */
+ if (ret > 0) {
+
+ /* trigger POLLIN events */
+ q = queue;
+ while (q) {
+ if (q->ev) { /* sanity check */
+
+ /* check if the event has been triggered */
+ if (FD_ISSET(q->ev->fd, ¤t_fds)) {
+
+ /* fire the event */
+ fpm_event_fire(q->ev);
+
+ /* sanity check */
+ if (fpm_globals.parent_pid != getpid()) {
+ return -2;
+ }
+ }
+ }
+ q = q->next; /* iterate */
+ }
+ }
+ return ret;
+
+}
+/* }}} */
+
+/*
+ * Add a FD to the fd set
+ */
+static int fpm_event_select_add(struct fpm_event_s *ev) /* {{{ */
+{
+ /* check size limitation */
+ if (ev->fd >= FD_SETSIZE) {
+ zlog(ZLOG_ERROR, "select: not enough space in the select fd list (max = %d). Please consider using another event mechanism.", FD_SETSIZE);
+ return -1;
+ }
+
+ /* add the FD if not already in */
+ if (!FD_ISSET(ev->fd, &fds)) {
+ FD_SET(ev->fd, &fds);
+ ev->index = ev->fd;
+ }
+
+ return 0;
+}
+/* }}} */
+
+/*
+ * Remove a FD from the fd set
+ */
+static int fpm_event_select_remove(struct fpm_event_s *ev) /* {{{ */
+{
+ /* remove the fd if it's in */
+ if (FD_ISSET(ev->fd, &fds)) {
+ FD_CLR(ev->fd, &fds);
+ ev->index = -1;
+ }
+
+ return 0;
+}
+/* }}} */
+
+#endif /* HAVE_SELECT */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2011 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Jerome Loyet <jerome@loyet.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef FPM_EVENTS_SELECT_H
+#define FPM_EVENTS_SELECT_H
+
+#include "../fpm_config.h"
+#include "../fpm_events.h"
+
+struct fpm_event_module_s *fpm_event_select_module();
+
+#endif /* FPM_EVENTS_SELECT_H */
} else {
max = wp->running_children + nb_to_spawn;
}
+ } else if (wp->config->pm == PM_STYLE_ONDEMAND) {
+ if (!in_event_loop) { /* starting */
+ max = 0; /* do not create any child at startup */
+ } else {
+ max = wp->running_children + nb_to_spawn;
+ }
} else { /* PM_STYLE_STATIC */
max = wp->config->pm_max_children;
}
int fpm_children_create_initial(struct fpm_worker_pool_s *wp) /* {{{ */
{
+ if (wp->config->pm == PM_STYLE_ONDEMAND) {
+ wp->ondemand_event = (struct fpm_event_s *)malloc(sizeof(struct fpm_event_s));
+
+ if (!wp->ondemand_event) {
+ zlog(ZLOG_ERROR, "[pool %s] unable to malloc the ondemand socket event", wp->config->name);
+ // FIXME handle crash
+ return 1;
+ }
+
+ memset(wp->ondemand_event, 0, sizeof(struct fpm_event_s));
+ fpm_event_set(wp->ondemand_event, wp->listening_socket, FPM_EV_READ | FPM_EV_EDGE, fpm_pctl_on_socket_accept, wp);
+ wp->socket_event_set = 1;
+ fpm_event_add(wp->ondemand_event, 0);
+
+ return 1;
+ }
return fpm_children_make(wp, 0 /* not in event loop yet */, 0, 1);
}
/* }}} */
#include "fpm_shm.h"
#include "fpm_status.h"
#include "fpm_log.h"
+#include "fpm_events.h"
#include "zlog.h"
#define STR2STR(a) (a ? a : "undefined")
static int fpm_conf_load_ini_file(char *filename TSRMLS_DC);
static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset);
+static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset);
static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset);
static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset);
static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset);
{ "daemonize", &fpm_conf_set_boolean, GO(daemonize) },
{ "rlimit_files", &fpm_conf_set_integer, GO(rlimit_files) },
{ "rlimit_core", &fpm_conf_set_rlimit_core, GO(rlimit_core) },
+ { "events.mechanism", &fpm_conf_set_string, GO(events_mechanism) },
{ 0, 0, 0 }
};
{ "pm.start_servers", &fpm_conf_set_integer, WPO(pm_start_servers) },
{ "pm.min_spare_servers", &fpm_conf_set_integer, WPO(pm_min_spare_servers) },
{ "pm.max_spare_servers", &fpm_conf_set_integer, WPO(pm_max_spare_servers) },
+ { "pm.process_idle_timeout", &fpm_conf_set_time, WPO(pm_process_idle_timeout) },
{ "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) },
{ "pm.status_path", &fpm_conf_set_string, WPO(pm_status_path) },
{ "ping.path", &fpm_conf_set_string, WPO(ping_path) },
}
/* }}} */
+static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset) /* {{{ */
+{
+ char *val = Z_STRVAL_P(value);
+ char *p;
+
+ for (p = val; *p; p++) {
+ if ( p == val && *p == '-' ) continue;
+ if (*p < '0' || *p > '9') {
+ return "is not a valid number (greater or equal than zero)";
+ }
+ }
+ * (long int *) ((char *) *config + offset) = atol(val);
+ return NULL;
+}
+/* }}} */
+
static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* {{{ */
{
char *val = Z_STRVAL_P(value);
c->pm = PM_STYLE_STATIC;
} else if (!strcasecmp(val, "dynamic")) {
c->pm = PM_STYLE_DYNAMIC;
+ } else if (!strcasecmp(val, "ondemand")) {
+ c->pm = PM_STYLE_ONDEMAND;
} else {
- return "invalid process manager (static or dynamic)";
+ return "invalid process manager (static, dynamic or ondemand)";
}
return NULL;
}
memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s));
wp->config->listen_backlog = FPM_BACKLOG_DEFAULT;
+ wp->config->pm_process_idle_timeout = 10; /* 10s by default */
if (!fpm_worker_all_pools) {
fpm_worker_all_pools = wp;
}
/* pm */
- if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC) {
- zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static or dynamic)", wp->config->name);
+ if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC && wp->config->pm != PM_STYLE_ONDEMAND) {
+ zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static, dynamic or ondemand)", wp->config->name);
return -1;
}
zlog(ZLOG_ALERT, "[pool %s] pm.start_servers(%d) must not be less than pm.min_spare_servers(%d) and not greater than pm.max_spare_servers(%d)", wp->config->name, config->pm_start_servers, config->pm_min_spare_servers, config->pm_max_spare_servers);
return -1;
}
+ } else if (wp->config->pm == PM_STYLE_ONDEMAND) {
+ struct fpm_worker_pool_config_s *config = wp->config;
+
+ if (!fpm_event_support_edge_trigger()) {
+ zlog(ZLOG_ALERT, "[pool %s] ondemand process manager can ONLY be used when events.mechanisme is either epoll (Linux) or kqueue (*BSD).", wp->config->name);
+ return -1;
+ }
+
+ if (config->pm_process_idle_timeout < 1) {
+ zlog(ZLOG_ALERT, "[pool %s] pm.process_idle_timeout(%ds) must be greater than 0s", wp->config->name, config->pm_process_idle_timeout);
+ return -1;
+ }
+
+ if (config->listen_backlog < FPM_BACKLOG_DEFAULT) {
+ zlog(ZLOG_WARNING, "[pool %s] listen.backlog(%d) was too low for the ondemand process manager. I updated it for you to %d.", wp->config->name, config->listen_backlog, FPM_BACKLOG_DEFAULT);
+ config->listen_backlog = FPM_BACKLOG_DEFAULT;
+ }
+ /* certainely useless but proper */
+ config->pm_start_servers = 0;
+ config->pm_min_spare_servers = 0;
+ config->pm_max_spare_servers = 0;
}
/* status */
return -1;
}
+ if (0 > fpm_event_pre_init(fpm_global_config.events_mechanism)) {
+ return -1;
+ }
+
if (0 > fpm_conf_process_all_pools()) {
return -1;
}
{
free(fpm_global_config.pid_file);
free(fpm_global_config.error_log);
+ free(fpm_global_config.events_mechanism);
fpm_global_config.pid_file = 0;
fpm_global_config.error_log = 0;
#ifdef HAVE_SYSLOG_H
zlog(ZLOG_NOTICE, "\tdaemonize = %s", BOOL2STR(fpm_global_config.daemonize));
zlog(ZLOG_NOTICE, "\trlimit_files = %d", fpm_global_config.rlimit_files);
zlog(ZLOG_NOTICE, "\trlimit_core = %d", fpm_global_config.rlimit_core);
+ zlog(ZLOG_NOTICE, "\tevents.mechanism = %s", fpm_event_machanism_name());
zlog(ZLOG_NOTICE, " ");
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
zlog(ZLOG_NOTICE, "\tpm.start_servers = %d", wp->config->pm_start_servers);
zlog(ZLOG_NOTICE, "\tpm.min_spare_servers = %d", wp->config->pm_min_spare_servers);
zlog(ZLOG_NOTICE, "\tpm.max_spare_servers = %d", wp->config->pm_max_spare_servers);
+ zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d", wp->config->pm_process_idle_timeout);
zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests);
zlog(ZLOG_NOTICE, "\tpm.status_path = %s", STR2STR(wp->config->pm_status_path));
zlog(ZLOG_NOTICE, "\tping.path = %s", STR2STR(wp->config->ping_path));
#include <stdint.h>
#include "php.h"
-#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : "dynamic")
+#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : (a == PM_STYLE_DYNAMIC ? "dynamic" : "ondemand"))
#define FPM_CONF_MAX_PONG_LENGTH 64
int daemonize;
int rlimit_files;
int rlimit_core;
+ char *events_mechanism;
};
extern struct fpm_global_config_s fpm_global_config;
int pm_start_servers;
int pm_min_spare_servers;
int pm_max_spare_servers;
+ int pm_process_idle_timeout;
int pm_max_requests;
char *pm_status_path;
char *ping_path;
enum {
PM_STYLE_STATIC = 1,
- PM_STYLE_DYNAMIC = 2
+ PM_STYLE_DYNAMIC = 2,
+ PM_STYLE_ONDEMAND = 3
};
int fpm_conf_init_main(int test_conf);
#include <string.h>
#include <php.h>
-#include <php_network.h>
#include "fpm.h"
#include "fpm_process_ctl.h"
#include "fpm_clock.h"
#include "fpm_log.h"
-#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout);
+#include "events/select.h"
+#include "events/poll.h"
+#include "events/epoll.h"
+#include "events/devpoll.h"
+#include "events/port.h"
+#include "events/kqueue.h"
-typedef struct fpm_event_queue_s {
- struct fpm_event_queue_s *prev;
- struct fpm_event_queue_s *next;
- struct fpm_event_s *ev;
-} fpm_event_queue;
+#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout);
static void fpm_event_cleanup(int which, void *arg);
static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg);
static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue);
-static int fpm_event_nfds_max;
+static struct fpm_event_module_s *module;
static struct fpm_event_queue_s *fpm_event_queue_timer = NULL;
static struct fpm_event_queue_s *fpm_event_queue_fd = NULL;
-static php_pollfd *fpm_event_ufds = NULL;
static void fpm_event_cleanup(int which, void *arg) /* {{{ */
{
- if (fpm_event_ufds) {
- free(fpm_event_ufds);
- }
fpm_event_queue_destroy(&fpm_event_queue_timer);
fpm_event_queue_destroy(&fpm_event_queue_fd);
}
}
*queue = elt;
+ /* ask the event module to add the fd from its own queue */
+ if (*queue == fpm_event_queue_fd && module->add) {
+ module->add(ev);
+ }
+
return 0;
}
/* }}} */
*queue = q->next;
(*queue)->prev = NULL;
}
+
+ /* ask the event module to remove the fd from its own queue */
+ if (*queue == fpm_event_queue_fd && module->remove) {
+ module->remove(ev);
+ }
+
free(q);
return 0;
}
if (!queue) {
return;
}
+
+ if (*queue == fpm_event_queue_fd && module->clean) {
+ module->clean();
+ }
+
q = *queue;
while (q) {
tmp = q;
}
/* }}} */
+int fpm_event_pre_init(char *machanism) /* {{{ */
+{
+ /* kqueue */
+ module = fpm_event_kqueue_module();
+ if (module) {
+ if (!machanism || strcasecmp(module->name, machanism) == 0) {
+ return 0;
+ }
+ }
+
+ /* port */
+ module = fpm_event_port_module();
+ if (module) {
+ if (!machanism || strcasecmp(module->name, machanism) == 0) {
+ return 0;
+ }
+ }
+
+ /* epoll */
+ module = fpm_event_epoll_module();
+ if (module) {
+ if (!machanism || strcasecmp(module->name, machanism) == 0) {
+ return 0;
+ }
+ }
+
+ /* /dev/poll */
+ module = fpm_event_devpoll_module();
+ if (module) {
+ if (!machanism || strcasecmp(module->name, machanism) == 0) {
+ return 0;
+ }
+ }
+
+ /* poll */
+ module = fpm_event_poll_module();
+ if (module) {
+ if (!machanism || strcasecmp(module->name, machanism) == 0) {
+ return 0;
+ }
+ }
+
+ /* select */
+ module = fpm_event_select_module();
+ if (module) {
+ if (!machanism || strcasecmp(module->name, machanism) == 0) {
+ return 0;
+ }
+ }
+
+ if (machanism) {
+ zlog(ZLOG_ERROR, "event mechanism '%s' is not available on this system", machanism);
+ } else {
+ zlog(ZLOG_ERROR, "unable to find a suitable event mechanism on this system");
+ }
+ return -1;
+}
+/* }} */
+
+const char *fpm_event_machanism_name() /* {{{ */
+{
+ return module ? module->name : NULL;
+}
+/* }}} */
+
+int fpm_event_support_edge_trigger() /* {{{ */
+{
+ return module ? module->support_edge_trigger : 0;
+}
+/* }}} */
+
int fpm_event_init_main() /* {{{ */
{
struct fpm_worker_pool_s *wp;
+ int max;
+
+ if (!module) {
+ zlog(ZLOG_ERROR, "no event module found");
+ return -1;
+ }
+
+ if (!module->wait) {
+ zlog(ZLOG_ERROR, "Incomplete event implementation. Please open a bug report on https://bugs.php.net.");
+ return -1;
+ }
/* count the max number of necessary fds for polling */
- fpm_event_nfds_max = 1; /* only one FD is necessary at startup for the master process signal pipe */
+ max = 1; /* only one FD is necessary at startup for the master process signal pipe */
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
if (!wp->config) continue;
if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) {
- fpm_event_nfds_max += (wp->config->pm_max_children * 2);
+ max += (wp->config->pm_max_children * 2);
}
}
- /* malloc the max number of necessary fds for polling */
- fpm_event_ufds = malloc(sizeof(php_pollfd) * fpm_event_nfds_max);
- if (!fpm_event_ufds) {
- zlog(ZLOG_SYSERROR, "Error while initializing events: malloc() failed");
+ if (module->init(max) < 0) {
+ zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name);
return -1;
}
- zlog(ZLOG_DEBUG, "%d fds have been reserved", fpm_event_nfds_max);
+ zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max);
if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) {
return -1;
struct timeval tmp;
struct timeval now;
unsigned long int timeout;
- int i, ret;
+ int ret;
/* sanity check */
if (fpm_globals.parent_pid != getpid()) {
timeout = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000) + 1;
}
- /* init fpm_event_ufds for php_poll2 */
- memset(fpm_event_ufds, 0, sizeof(php_pollfd) * fpm_event_nfds_max);
- i = 0;
- q = fpm_event_queue_fd;
- while (q && i < fpm_event_nfds_max) {
- fpm_event_ufds[i].fd = q->ev->fd;
- fpm_event_ufds[i].events = POLLIN;
- q->ev->index = i++;
- q = q->next;
+ ret = module->wait(fpm_event_queue_fd, timeout);
+
+ /* is a child, nothing to do here */
+ if (ret == -2) {
+ return;
}
- /* wait for inconming event or timeout */
- if ((ret = php_poll2(fpm_event_ufds, i, timeout)) == -1) {
- if (errno != EINTR) {
- zlog(ZLOG_SYSERROR, "failed to wait for events: php_poll2()");
- }
- } else if (ret > 0) {
-
- /* trigger POLLIN events */
- q = fpm_event_queue_fd;
- while (q) {
- if (q->ev && q->ev->index >= 0 && q->ev->index < fpm_event_nfds_max) {
- if (q->ev->fd == fpm_event_ufds[q->ev->index].fd) {
- if (fpm_event_ufds[q->ev->index].revents & POLLIN) {
- fpm_event_fire(q->ev);
- /* sanity check */
- if (fpm_globals.parent_pid != getpid()) {
- return;
- }
- }
- }
- q->ev->index = -1;
- }
- q = q->next;
- }
+ if (ret > 0) {
+ zlog(ZLOG_DEBUG, "event module triggered %d events", ret);
}
/* trigger timers */
int fpm_event_del(struct fpm_event_s *ev) /* {{{ */
{
- if (fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) {
+ if (ev->index >= 0 && fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) {
return -1;
}
- if (fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) {
+ if (ev->index < 0 && fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) {
return -1;
}
#define FPM_EV_TIMEOUT (1 << 0)
#define FPM_EV_READ (1 << 1)
#define FPM_EV_PERSIST (1 << 2)
+#define FPM_EV_EDGE (1 << 3)
#define fpm_event_set_timer(ev, flags, cb, arg) fpm_event_set((ev), -1, (flags), (cb), (arg))
short which; /* type of event */
};
+typedef struct fpm_event_queue_s {
+ struct fpm_event_queue_s *prev;
+ struct fpm_event_queue_s *next;
+ struct fpm_event_s *ev;
+} fpm_event_queue;
+
+struct fpm_event_module_s {
+ const char *name;
+ int support_edge_trigger;
+ int (*init)(int max_fd);
+ int (*clean)(void);
+ int (*wait)(struct fpm_event_queue_s *queue, unsigned long int timeout);
+ int (*add)(struct fpm_event_s *ev);
+ int (*remove)(struct fpm_event_s *ev);
+};
+
void fpm_event_loop(int err);
void fpm_event_fire(struct fpm_event_s *ev);
int fpm_event_init_main();
int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg);
int fpm_event_add(struct fpm_event_s *ev, unsigned long int timeout);
int fpm_event_del(struct fpm_event_s *ev);
+int fpm_event_pre_init(char *machanism);
+const char *fpm_event_machanism_name();
+int fpm_event_support_edge_trigger();
#endif
}
fpm_scoreboard_update(idle, active, cur_lq, -1, -1, -1, FPM_SCOREBOARD_ACTION_SET, wp->scoreboard);
+ /* this is specific to PM_STYLE_ONDEMAND */
+ if (wp->config->pm == PM_STYLE_ONDEMAND) {
+ struct timeval last, now;
+
+ zlog(ZLOG_DEBUG, "[pool %s] currently %d active children, %d spare children", wp->config->name, active, idle);
+
+ if (!last_idle_child) continue;
+
+ fpm_request_last_activity(last_idle_child, &last);
+ fpm_clock_get(&now);
+ if (last.tv_sec < now.tv_sec - wp->config->pm_process_idle_timeout) {
+ last_idle_child->idle_kill = 1;
+ fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT);
+ }
+
+ continue;
+ }
/* the rest is only used by PM_STYLE_DYNAMIC */
if (wp->config->pm != PM_STYLE_DYNAMIC) continue;
}
/* }}} */
+void fpm_pctl_on_socket_accept(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
+{
+ struct fpm_worker_pool_s *wp = (struct fpm_worker_pool_s *)arg;
+ struct fpm_child_s *child;
+
+
+ if (fpm_globals.parent_pid != getpid()) {
+ /* prevent a event race condition when child process
+ * have not set up its own event loop */
+ return;
+ }
+
+ wp->socket_event_set = 0;
+
+// zlog(ZLOG_DEBUG, "[pool %s] heartbeat running_children=%d", wp->config->name, wp->running_children);
+
+ if (wp->running_children >= wp->config->pm_max_children) {
+ if (!wp->warn_max_children) {
+ fpm_scoreboard_update(0, 0, 0, 0, 0, 1, FPM_SCOREBOARD_ACTION_INC, wp->scoreboard);
+ zlog(ZLOG_WARNING, "[pool %s] server reached max_children setting (%d), consider raising it", wp->config->name, wp->config->pm_max_children);
+ wp->warn_max_children = 1;
+ }
+
+ return;
+ }
+
+ for (child = wp->children; child; child = child->next) {
+ /* if there is at least on idle child, it will handle the connection, stop here */
+ if (fpm_request_is_idle(child)) {
+ return;
+ }
+ }
+
+ wp->warn_max_children = 0;
+ fpm_children_make(wp, 1, 1, 1);
+
+ if (fpm_globals.is_child) {
+ return;
+ }
+
+ zlog(ZLOG_DEBUG, "[pool %s] got accept without idle child available .... I forked", wp->config->name);
+}
+/* }}} */
+
void fpm_pctl_kill_all(int signo);
void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg);
void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg);
+void fpm_pctl_on_socket_accept(struct fpm_event_s *ev, short which, void *arg);
int fpm_pctl_child_exited();
int fpm_pctl_init_main();
return proc->request_stage == FPM_REQUEST_ACCEPTING;
}
/* }}} */
+
+int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv) /* {{{ */
+{
+ struct fpm_scoreboard_proc_s *proc;
+
+ if (!tv) return -1;
+
+ proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i);
+ if (!proc) {
+ return -1;
+ }
+
+ *tv = proc->tv;
+
+ return 1;
+}
+/* }}} */
void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *tv, int terminate_timeout, int slowlog_timeout);
int fpm_request_is_idle(struct fpm_child_s *child);
const char *fpm_request_get_stage_name(int stage);
+int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv);
enum fpm_request_stage_e {
FPM_REQUEST_ACCEPTING = 1,
struct fpm_scoreboard_s *scoreboard;
int log_fd;
char **limit_extensions;
+
+ /* for ondemand PM */
+ struct fpm_event_s *ondemand_event;
+ int socket_event_set;
};
struct fpm_worker_pool_s *fpm_worker_pool_alloc();
; Default Value: system defined value
;rlimit_core = 0
+; Specify the event mechanism FPM will use. The following is available:
+; - select (any POSIX os)
+; - poll (any POSIX os)
+; - epoll (linux >= 2.5.44)
+; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
+; - /dev/poll (Solaris >= 7)
+; - port (Solaris >= 10)
+; Default Value: not set (auto detection)
+; events.mechanism = epoll
+
;;;;;;;;;;;;;;;;;;;;
; Pool Definitions ;
;;;;;;;;;;;;;;;;;;;;
; Possible Values:
; static - a fixed number (pm.max_children) of child processes;
; dynamic - the number of child processes are set dynamically based on the
-; following directives:
+; following directives. With this process management, there will be
+; always at least 1 children.
; pm.max_children - the maximum number of children that can
; be alive at the same time.
; pm.start_servers - the number of children created on startup.
; state (waiting to process). If the number
; of 'idle' processes is greater than this
; number then some children will be killed.
+; ondemand - no children are created at startup. Children will be forked when
+; new requests will connect. The following parameter are used:
+; pm.max_children - the maximum number of children that
+; can be alive at the same time.
+; pm.process_idle_timeout - The number of seconds after which
+; an idle process will be killed.
; Note: This value is mandatory.
pm = dynamic
; The number of child processes to be created when pm is set to 'static' and the
-; maximum number of child processes to be created when pm is set to 'dynamic'.
+; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
-; Note: Used when pm is set to either 'static' or 'dynamic'
+; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 5
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 3
+
+; The number of seconds after which an idle process will be killed.
+; Note: Used only when pm is set to 'ondemand'
+; Default Value: 10s
+;pm.process_idle_timeout = 10s;
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For
; The URI to view the FPM status page. If this value is not set, no URI will be
; recognized as a status page. It shows the following informations:
; pool - the name of the pool;
-; process manager - static or dynamic;
+; process manager - static, dynamic or ondemand;
; start time - the date and time FPM has started;
; start since - number of seconds since FPM has started;
; accepted conn - the number of request accepted by the pool;
; has started;
; max children reached - number of times, the process limit has been reached,
; when pm tries to start more children (works only for
-; pm 'dynamic');
+; pm 'dynamic' and 'ondemand');
; Value are updated in real time.
; Example output:
; pool: www