summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2020-10-19 01:30:05 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2020-10-19 21:40:14 -0400
commitfc6612d7c712dc31cdba0db09bce4cdbb4e2b3ee (patch)
tree8cf99eaf3b74c4a4c02f9065254774afcb0faf51
parentd6f692f1c21c79f4dbf68071c7a48a4b2316311a (diff)
downloadlighttpd-git-fc6612d7c712dc31cdba0db09bce4cdbb4e2b3ee.tar.gz
[core] minimize pause during graceful restart
minimize pause during graceful restart for server.max-worker = 0 case The previous generation continues to accept new connections until the restarted parent signals that the restarted server is ready to accept new connections, and so the previous server should gracefully shutdown. This does not apply in the case of multiple workers. When there are multiple workers, they receive SIGINT to gracefully shut down and stop accepting new connections. While the listen sockets are kept open (and not closed and reopened), there is a small pause while the parent process restarts before it begins accepting new connections from the listen backlog. Note: there is a window during restart during which lighttpd may exit if it receives certain signals before it sets up signal handlers. future: might block signals (sigprocmask()) during restart, but if that is done, then care must be taken to unblock signals in restarted server as soon as signal handlers are set up and before any other children are created, e.g. by modules, or else signals must be explicitly unblocked in children. Also, during command line and config file processing, signals would be blocked, too, which might not be ideal.
-rw-r--r--src/server.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/src/server.c b/src/server.c
index 8b2aa660..1acac9bf 100644
--- a/src/server.c
+++ b/src/server.c
@@ -772,6 +772,18 @@ static void server_sockets_close (server *srv) {
}
__attribute_cold__
+static void server_graceful_signal_prev_generation (void)
+{
+ const char * const prev_gen = getenv("LIGHTTPD_PREV_GEN");
+ if (NULL == prev_gen) return;
+ pid_t pid = (pid_t)strtol(prev_gen, NULL, 10);
+ unsetenv("LIGHTTPD_PREV_GEN");
+ if (pid <= 0) return; /*(should not happen)*/
+ if (pid == waitpid(pid, NULL, WNOHANG)) return; /*(pid exited; unexpected)*/
+ kill(pid, SIGINT); /* signal previous generation for graceful shutdown */
+}
+
+__attribute_cold__
static int server_graceful_state_bg (server *srv) {
/*assert(graceful_restart);*/
/*(SIGUSR1 set to SIG_IGN in workers, so should not reach here if worker)*/
@@ -833,6 +845,16 @@ static int server_graceful_state_bg (server *srv) {
if (pid) { /* original process */
if (pid < 0) return 0;
network_socket_activation_to_env(srv);
+ /* save pid of original server in environment so that it can be
+ * signalled by restarted server once restarted server is ready
+ * to accept new connections */
+ server_graceful_signal_prev_generation();/*(expect no prev gen active)*/
+ if (0 == srv->srvconf.max_worker) {
+ buffer * const tb = srv->tmp_buf;
+ buffer_clear(tb);
+ buffer_append_int(tb, pid);
+ setenv("LIGHTTPD_PREV_GEN", tb->ptr, 1);
+ }
/*while (waitpid(pid, NULL, 0) < 0 && errno == EINTR) ;*//* detach? */
execv(argv[0], argv);
_exit(1);
@@ -840,7 +862,10 @@ static int server_graceful_state_bg (server *srv) {
/* else child/grandchild */
/*if (-1 == setsid()) _exit(1);*//* should we detach? */
- server_sockets_close(srv); /*(close before parent reaps pid in waitpid)*/
+ /* Note: restarted server will fail with socket-in-use error if
+ * server.systemd-socket-activation not enabled in restarted server */
+ if (0 != srv->srvconf.max_worker)
+ server_sockets_close(srv);/*(close before parent reaps pid in waitpid)*/
/*if (0 != fork()) _exit(0);*//* should we detach? */
/*(grandchild is now backgrounded and detached from original process)*/
@@ -862,6 +887,11 @@ static int server_graceful_state_bg (server *srv) {
"[note] pid %lld continuing to handle %u connection(s) in progress",
(long long)getpid(), srv->conns.used);
+ if (0 == srv->srvconf.max_worker) {
+ /* reset graceful_shutdown; wait for signal from restarted server */
+ srv->graceful_expire_ts = 0;
+ graceful_shutdown = 0;
+ }
graceful_restart = 0;
return 1;
}
@@ -1490,6 +1520,7 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
int child = 0;
unsigned int timer = 0;
for (int n = 0; n < npids; ++n) pids[n] = -1;
+ server_graceful_signal_prev_generation();
while (!child && !srv_shutdown && !graceful_shutdown) {
if (num_childs > 0) {
switch ((pid = fork())) {
@@ -1704,6 +1735,9 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
oneshot_fd = -1;
}
+ if (0 == srv->srvconf.max_worker)
+ server_graceful_signal_prev_generation();
+
return 1;
}
@@ -1834,7 +1868,7 @@ static void server_main_loop (server * const srv) {
if (graceful_shutdown) {
server_graceful_state(srv);
- if (0 == srv->conns.used) {
+ if (0 == srv->conns.used && graceful_shutdown) {
/* we are in graceful shutdown phase and all connections are closed
* we are ready to terminate without harming anyone */
srv_shutdown = 1;