summaryrefslogtreecommitdiff
path: root/sapi
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-02-04 15:18:45 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-02-04 15:22:34 +0100
commit5cb25a2d32df8073df7c191dd6c7694b4495af62 (patch)
tree5adba558b35e119da1761b9a5c9eaac88243bfe5 /sapi
parent767ddb1cd53ffc5fe4f6ca2e3072be68586f38d2 (diff)
downloadphp-git-5cb25a2d32df8073df7c191dd6c7694b4495af62.tar.gz
Fix CLI server worker support
If we create separate listening sockets in each worker using SO_REUSEADDR, then an incoming connection may be load-balanced to a process that is already busy, either due to a long-running request, or because it is a recursive request (in which case we would deadlock). Instead, only create one listening socket, and only create worker forks afterwards. This way the incoming request will be served by one of the workers that is currently listening for an incoming connection.
Diffstat (limited to 'sapi')
-rw-r--r--sapi/cli/php_cli_server.c106
1 files changed, 47 insertions, 59 deletions
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
index a32b51e3d3..4fe975d6a4 100644
--- a/sapi/cli/php_cli_server.c
+++ b/sapi/cli/php_cli_server.c
@@ -498,58 +498,7 @@ const zend_function_entry server_additional_functions[] = {
static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */
{
- char *workers;
-
- if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) {
- return FAILURE;
- }
-
- if ((workers = getenv("PHP_CLI_SERVER_WORKERS"))) {
-#ifndef SO_REUSEPORT
- fprintf(stderr, "platform does not support SO_REUSEPORT, cannot create workers\n");
-#elif HAVE_FORK
- ZEND_ATOL(php_cli_server_workers_max, workers);
-
- if (php_cli_server_workers_max > 1) {
- zend_long php_cli_server_worker;
-
- php_cli_server_workers = calloc(
- php_cli_server_workers_max, sizeof(pid_t));
- if (!php_cli_server_workers) {
- php_cli_server_workers_max = 1;
-
- return SUCCESS;
- }
-
- php_cli_server_master = getpid();
-
- for (php_cli_server_worker = 0;
- php_cli_server_worker < php_cli_server_workers_max;
- php_cli_server_worker++) {
- pid_t pid = fork();
-
- if (pid == FAILURE) {
- /* no more forks allowed, work with what we have ... */
- php_cli_server_workers_max =
- php_cli_server_worker + 1;
- return SUCCESS;
- } else if (pid == SUCCESS) {
- return SUCCESS;
- } else {
- php_cli_server_workers[
- php_cli_server_worker
- ] = pid;
- }
- }
- } else {
- fprintf(stderr, "number of workers must be larger than 1\n");
- }
-#else
- fprintf(stderr, "forking is not supported on this platform\n");
-#endif
- }
-
- return SUCCESS;
+ return php_module_startup(sapi_module, &cli_server_module_entry, 1);
} /* }}} */
static size_t sapi_cli_server_ub_write(const char *str, size_t str_length) /* {{{ */
@@ -1317,13 +1266,6 @@ static php_socket_t php_network_listen_socket(const char *host, int *port, int s
}
#endif
-#if defined(HAVE_FORK) && defined(SO_REUSEPORT)
- if (php_cli_server_workers_max > 1) {
- int val = 1;
- setsockopt(retval, SOL_SOCKET, SO_REUSEPORT, (char*)&val, sizeof(val));
- }
-#endif
-
if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) {
err = php_socket_errno();
if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) {
@@ -2412,6 +2354,50 @@ static char *php_cli_server_parse_addr(const char *addr, int *pport) {
return pestrndup(addr, end - addr, 1);
}
+static void php_cli_server_startup_workers() {
+ char *workers = getenv("PHP_CLI_SERVER_WORKERS");
+ if (!workers) {
+ return;
+ }
+
+#if HAVE_FORK
+ ZEND_ATOL(php_cli_server_workers_max, workers);
+ if (php_cli_server_workers_max > 1) {
+ zend_long php_cli_server_worker;
+
+ php_cli_server_workers = calloc(
+ php_cli_server_workers_max, sizeof(pid_t));
+ if (!php_cli_server_workers) {
+ php_cli_server_workers_max = 1;
+ return;
+ }
+
+ php_cli_server_master = getpid();
+
+ for (php_cli_server_worker = 0;
+ php_cli_server_worker < php_cli_server_workers_max;
+ php_cli_server_worker++) {
+ pid_t pid = fork();
+
+ if (pid == FAILURE) {
+ /* no more forks allowed, work with what we have ... */
+ php_cli_server_workers_max =
+ php_cli_server_worker + 1;
+ return;
+ } else if (pid == SUCCESS) {
+ return;
+ } else {
+ php_cli_server_workers[php_cli_server_worker] = pid;
+ }
+ }
+ } else {
+ fprintf(stderr, "number of workers must be larger than 1\n");
+ }
+#else
+ fprintf(stderr, "forking is not supported on this platform\n");
+#endif
+}
+
static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router) /* {{{ */
{
int retval = SUCCESS;
@@ -2441,6 +2427,8 @@ static int php_cli_server_ctor(php_cli_server *server, const char *addr, const c
}
server->server_sock = server_sock;
+ php_cli_server_startup_workers();
+
err = php_cli_server_poller_ctor(&server->poller);
if (SUCCESS != err) {
goto out;