php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | |
Patch fpm-ondemand.v11.patch for FPM related Bug #52569Patch version 2011-07-14 22:27 UTC Return to Bug #52569 | Download this patchThis patch renders other patches obsolete Obsolete patches: Patch Revisions:Developer: fat@php.netIndex: sapi/fpm/php-fpm.conf.in =================================================================== --- sapi/fpm/php-fpm.conf.in (revision 313251) +++ sapi/fpm/php-fpm.conf.in (working copy) @@ -82,6 +82,16 @@ ; 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 ; ;;;;;;;;;;;;;;;;;;;; @@ -150,7 +160,8 @@ ; 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. @@ -162,17 +173,23 @@ ; 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 @@ -190,6 +207,11 @@ ; 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 @@ -200,7 +222,7 @@ ; 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; @@ -216,7 +238,7 @@ ; 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 Index: sapi/fpm/fpm/fpm_request.h =================================================================== --- sapi/fpm/fpm/fpm_request.h (revision 313251) +++ sapi/fpm/fpm/fpm_request.h (working copy) @@ -18,6 +18,7 @@ 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, Index: sapi/fpm/fpm/fpm_process_ctl.c =================================================================== --- sapi/fpm/fpm/fpm_process_ctl.c (revision 313251) +++ sapi/fpm/fpm/fpm_process_ctl.c (working copy) @@ -355,7 +355,24 @@ 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; @@ -472,3 +489,47 @@ } /* }}} */ +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); +} +/* }}} */ + Index: sapi/fpm/fpm/events/kqueue.c =================================================================== --- sapi/fpm/fpm/events/kqueue.c (revision 0) +++ sapi/fpm/fpm/events/kqueue.c (revision 0) @@ -0,0 +1,208 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/select.c =================================================================== --- sapi/fpm/fpm/events/select.c (revision 0) +++ sapi/fpm/fpm/events/select.c (revision 0) @@ -0,0 +1,175 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/epoll.h =================================================================== --- sapi/fpm/fpm/events/epoll.h (revision 0) +++ sapi/fpm/fpm/events/epoll.h (revision 0) @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/kqueue.h =================================================================== --- sapi/fpm/fpm/events/kqueue.h (revision 0) +++ sapi/fpm/fpm/events/kqueue.h (revision 0) @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/port.c =================================================================== --- sapi/fpm/fpm/events/port.c (revision 0) +++ sapi/fpm/fpm/events/port.c (revision 0) @@ -0,0 +1,185 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/select.h =================================================================== --- sapi/fpm/fpm/events/select.h (revision 0) +++ sapi/fpm/fpm/events/select.h (revision 0) @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/devpoll.c =================================================================== --- sapi/fpm/fpm/events/devpoll.c (revision 0) +++ sapi/fpm/fpm/events/devpoll.c (revision 0) @@ -0,0 +1,248 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/poll.c =================================================================== --- sapi/fpm/fpm/events/poll.c (revision 0) +++ sapi/fpm/fpm/events/poll.c (revision 0) @@ -0,0 +1,276 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/port.h =================================================================== --- sapi/fpm/fpm/events/port.h (revision 0) +++ sapi/fpm/fpm/events/port.h (revision 0) @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/devpoll.h =================================================================== --- sapi/fpm/fpm/events/devpoll.h (revision 0) +++ sapi/fpm/fpm/events/devpoll.h (revision 0) @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/poll.h =================================================================== --- sapi/fpm/fpm/events/poll.h (revision 0) +++ sapi/fpm/fpm/events/poll.h (revision 0) @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/events/epoll.c =================================================================== --- sapi/fpm/fpm/events/epoll.c (revision 0) +++ sapi/fpm/fpm/events/epoll.c (revision 0) @@ -0,0 +1,211 @@ +/* + +----------------------------------------------------------------------+ + | 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 */ Index: sapi/fpm/fpm/fpm_status.c =================================================================== --- sapi/fpm/fpm/fpm_status.c (revision 313251) +++ sapi/fpm/fpm/fpm_status.c (working copy) @@ -352,7 +352,7 @@ now_epoch = time(NULL); spprintf(&buffer, 0, short_syntax, scoreboard.pool, - scoreboard.pm == PM_STYLE_STATIC ? "static" : "dynamic", + scoreboard.pm == PM_STYLE_STATIC ? "static" : (scoreboard.pm == PM_STYLE_DYNAMIC ? "dynamic" : "ondemand"), time_buffer, now_epoch - scoreboard.start_epoch, scoreboard.requests, Index: sapi/fpm/fpm/fpm_conf.c =================================================================== --- sapi/fpm/fpm/fpm_conf.c (revision 313251) +++ sapi/fpm/fpm/fpm_conf.c (working copy) @@ -43,16 +43,18 @@ #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") #define BOOL2STR(a) (a ? "yes" : "no") -#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : "dynamic") +#define PM2STR(a) (a == PM_STYLE_STATIC ? "static" : (a == PM_STYLE_DYNAMIC ? "dynamic" : "ondemand")) #define GO(field) offsetof(struct fpm_global_config_s, field) #define WPO(field) offsetof(struct fpm_worker_pool_config_s, field) 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); @@ -66,7 +68,7 @@ struct fpm_global_config_s fpm_global_config = { .daemonize = 1, #ifdef HAVE_SYSLOG_H - .syslog_facility = -1 + .syslog_facility = -1, #endif }; static struct fpm_worker_pool_s *current_wp = NULL; @@ -89,6 +91,7 @@ #endif { "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 } }; @@ -116,6 +119,7 @@ { "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.status_path", &fpm_conf_set_string, WPO(pm_status_path) }, { "ping.path", &fpm_conf_set_string, WPO(ping_path) }, { "ping.response", &fpm_conf_set_string, WPO(ping_response) }, @@ -223,6 +227,22 @@ } /* }}} */ +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); @@ -475,8 +495,10 @@ 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; } @@ -542,6 +564,7 @@ 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; @@ -702,8 +725,8 @@ return -1; } - 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; } @@ -744,7 +767,28 @@ 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; } if (wp->config->slowlog && *wp->config->slowlog) { @@ -1041,6 +1085,10 @@ return -1; } + if (0 > fpm_event_pre_init(fpm_global_config.events_mechanism)) { + return -1; + } + if (0 > fpm_conf_process_all_pools()) { return -1; } @@ -1063,6 +1111,7 @@ { 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 @@ -1398,6 +1447,7 @@ zlog(ZLOG_NOTICE, "\temergency_restart_threshold = %d", fpm_global_config.emergency_restart_threshold); 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) { @@ -1421,6 +1471,7 @@ 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.status_path = %s", STR2STR(wp->config->pm_status_path)); zlog(ZLOG_NOTICE, "\tping.path = %s", STR2STR(wp->config->ping_path)); zlog(ZLOG_NOTICE, "\tping.response = %s", STR2STR(wp->config->ping_response)); Index: sapi/fpm/fpm/fpm_process_ctl.h =================================================================== --- sapi/fpm/fpm/fpm_process_ctl.h (revision 313251) +++ sapi/fpm/fpm/fpm_process_ctl.h (working copy) @@ -22,6 +22,7 @@ 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(); Index: sapi/fpm/fpm/fpm_conf.h =================================================================== --- sapi/fpm/fpm/fpm_conf.h (revision 313251) +++ sapi/fpm/fpm/fpm_conf.h (working copy) @@ -32,6 +32,7 @@ #endif int rlimit_files; int rlimit_core; + char *events_mechanism; }; extern struct fpm_global_config_s fpm_global_config; @@ -56,6 +57,7 @@ int pm_start_servers; int pm_min_spare_servers; int pm_max_spare_servers; + int pm_process_idle_timeout; char *ping_path; char *ping_response; char *access_log; @@ -80,7 +82,8 @@ 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); Index: sapi/fpm/fpm/fpm_events.c =================================================================== --- sapi/fpm/fpm/fpm_events.c (revision 313251) +++ sapi/fpm/fpm/fpm_events.c (working copy) @@ -10,7 +10,6 @@ #include <string.h> #include <php.h> -#include <php_network.h> #include "fpm.h" #include "fpm_process_ctl.h" @@ -23,14 +22,15 @@ #include "fpm_clock.h" #include "fpm_log.h" +#include "events/select.h" +#include "events/poll.h" +#include "events/epoll.h" +#include "events/devpoll.h" +#include "events/port.h" +#include "events/kqueue.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); @@ -38,16 +38,12 @@ 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); } @@ -166,6 +162,11 @@ } *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; } /* }}} */ @@ -189,6 +190,12 @@ *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; } @@ -205,6 +212,11 @@ if (!queue) { return; } + + if (*queue == fpm_event_queue_fd && module->clean) { + module->clean(); + } + q = *queue; while (q) { tmp = q; @@ -216,27 +228,107 @@ } /* }}} */ +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, "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; @@ -273,7 +365,7 @@ struct timeval tmp; struct timeval now; unsigned long int timeout; - int i, ret; + int ret; /* sanity check */ if (fpm_globals.parent_pid != getpid()) { @@ -304,41 +396,15 @@ 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_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; - } + if (ret > 0) { + zlog(ZLOG_DEBUG, "event module triggered %d events", ret); } /* trigger timers */ @@ -446,11 +512,11 @@ 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; } Index: sapi/fpm/fpm/fpm_worker_pool.h =================================================================== --- sapi/fpm/fpm/fpm_worker_pool.h (revision 313251) +++ sapi/fpm/fpm/fpm_worker_pool.h (working copy) @@ -38,6 +38,10 @@ 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(); Index: sapi/fpm/fpm/fpm_events.h =================================================================== --- sapi/fpm/fpm/fpm_events.h (revision 313251) +++ sapi/fpm/fpm/fpm_events.h (working copy) @@ -8,6 +8,7 @@ #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)) @@ -22,11 +23,30 @@ 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 Index: sapi/fpm/fpm/fpm_request.c =================================================================== --- sapi/fpm/fpm/fpm_request.c (revision 313251) +++ sapi/fpm/fpm/fpm_request.c (working copy) @@ -295,3 +295,20 @@ 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; +} +/* }}} */ Index: sapi/fpm/fpm/fpm_children.c =================================================================== --- sapi/fpm/fpm/fpm_children.c (revision 313251) +++ sapi/fpm/fpm/fpm_children.c (working copy) @@ -370,6 +370,12 @@ } 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; } @@ -413,6 +419,22 @@ 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); } /* }}} */ Index: sapi/fpm/config.m4 =================================================================== --- sapi/fpm/config.m4 (revision 313251) +++ sapi/fpm/config.m4 (working copy) @@ -366,7 +366,172 @@ ]) 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_MSG_RESULT($PHP_FPM) @@ -379,6 +544,12 @@ 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) @@ -446,6 +617,12 @@ 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)') |
Copyright © 2001-2024 The PHP Group All rights reserved. |
Last updated: Sat Dec 21 17:01:58 2024 UTC |