From nobody Tue Dec 10 23:38:01 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Y7FXT3hzXz5g2yN; Tue, 10 Dec 2024 23:38:01 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Y7FXT2KwFz4lZc; Tue, 10 Dec 2024 23:38:01 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1733873881; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BMa7bon8cqtsItyGlVVuUaw0Ggje2t+nuwNRdrOpHVI=; b=M4UXULhkDhM2szE67Rn7sJiq0b+J6LqM+ja6ZVEzjoP00hV8xwT0ncql21Cztf0XvfPz83 B9zdfxrFyufxjNOZTZ1bz9WZJL48fNoiM2SxETTIqgONy4R6dusVLVAYvskGJ1NRBc6wir u0vmLY7cgk/43CYsIlOd/FHsRNLrMwVoj+qi6CT8BS1I20oYuMzEDU/kvcssF0raq8G+BL IMRekUiMo/N8wjZJj1MwKszeEXjM5MyRzSDo1iN+APmkehynZM19PKu1F1yNl7c9uT6ZcW 4q4C3slp85ud+UK/3kVGKgR7lGUB5DZMos17tnR4AVfom6T8ZyymoGH8nPTlzQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1733873881; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BMa7bon8cqtsItyGlVVuUaw0Ggje2t+nuwNRdrOpHVI=; b=CU/Dx3tBfvZmY7gkU6maLaGijEjIdPrI9bQxbAIsb3XnYI8f0GOnxeOeeI2xKKwvE+q7UL tgq6x5XRehIddUKvQV7VccJOuVKh4ECs0uXs+zIHMhnVVgcZFmvAO2qYh7mvrHZjw2vSQb zLQEsfKlrhJa5vGh5pyIkf/5FOurPjMaRIj+/41yiiz3uuqypngtdAQzv3bsjzwWLZoXNC /n9DNwgGHE/rPhorSyJY5EVrodzLtjB446ITdy4UwQTW50/zAz/zvFvI8XzBzHO0QMoee7 jtZwNZeeW3H4wdZM6XK84F0L55m+xLQpxm6USfaQ8NUCSvF5JEX3+sUwUVKoCQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1733873881; a=rsa-sha256; cv=none; b=U+Twbw2ssvp06Wu1CsuH+hMXxIkHt0Iqrc0799JwUnuqe3ZcfuI92BHVIpt4u+UKacQSr9 cLrf0K1EL+/WR5UBgw7RL+wLFXX9FjW3BD0KgERrEsZv9Mh6NsyYhBbUZEISUPxf987VUy QaMVKCrGeRy8MKxlOUzW80ZfNnu9uzXzQDsNtUSiMFuItZlNPG5Bn/uu+tCNbfzeu67V+1 mP24Vc/QyNci5pr84LG2uz101WON9TIpJyArN45AV+xYsV/7zcVRr3LQwSZoRB2kgl9IMn qKcqI1x2zrU+hla912/u2pBF3odckhhZM9VtmHDy3dAEAaJL3CwaBKFoK2bvPA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Y7FXT1ddLzkQk; Tue, 10 Dec 2024 23:38:01 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 4BANc1db019833; Tue, 10 Dec 2024 23:38:01 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 4BANc19s019830; Tue, 10 Dec 2024 23:38:01 GMT (envelope-from git) Date: Tue, 10 Dec 2024 23:38:01 GMT Message-Id: <202412102338.4BANc19s019830@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kyle Evans Subject: git: 7ea2874eadf9 - stable/14 - daemon: stop rebuilding the kqueue every restart of the child List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 7ea2874eadf901b1187772670169b6fc3a44d917 Auto-Submitted: auto-generated The branch stable/14 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=7ea2874eadf901b1187772670169b6fc3a44d917 commit 7ea2874eadf901b1187772670169b6fc3a44d917 Author: Kyle Evans AuthorDate: 2024-11-19 19:51:27 +0000 Commit: Kyle Evans CommitDate: 2024-12-10 23:05:46 +0000 daemon: stop rebuilding the kqueue every restart of the child We populate the kqueue with all of four kevents: three signal handlers and one for read of the child pipe. Every time we start the child, we rebuild this kqueue from scratch for the child and tear it down before we exit and check if we need to restart the child. As a consequence, we effectively drop any of the signals we're interested in between restarts. Push the kqueue out into the daemon state to avoid losing any signal events in the process, and reimplement the restart timer in terms of kqueue timers. The pipe read event will be automatically deleted upon last close, which leaves us with only the signal events that really get retained between restarts of the child. PR: 277959 Reviewed by: des, markj (cherry picked from commit bc1dfc316a2bba97773a14b96f5e976a52524be4) --- usr.sbin/daemon/daemon.c | 121 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 20 deletions(-) diff --git a/usr.sbin/daemon/daemon.c b/usr.sbin/daemon/daemon.c index 6d0ce2cc10e6..73524e3bd286 100644 --- a/usr.sbin/daemon/daemon.c +++ b/usr.sbin/daemon/daemon.c @@ -79,6 +79,7 @@ struct daemon_state { enum daemon_mode mode; int pid; int keep_cur_workdir; + int kqueue_fd; int restart_delay; int stdmask; int syslog_priority; @@ -104,6 +105,7 @@ static void daemon_terminate(struct daemon_state *); static void daemon_exec(struct daemon_state *); static bool daemon_is_child_dead(struct daemon_state *); static void daemon_set_child_pipe(struct daemon_state *); +static int daemon_setup_kqueue(void); static int pidfile_truncate(struct pidfh *); @@ -324,6 +326,8 @@ main(int argc, char *argv[]) /* Write out parent pidfile if needed. */ pidfile_write(state.parent_pidfh); + state.kqueue_fd = daemon_setup_kqueue(); + do { state.mode = MODE_SUPERVISE; daemon_eventloop(&state); @@ -379,27 +383,13 @@ daemon_eventloop(struct daemon_state *state) err(1, "pipe"); } - kq = kqueuex(KQUEUE_CLOEXEC); + kq = state->kqueue_fd; EV_SET(&event, state->pipe_fd[0], EVFILT_READ, EV_ADD|EV_CLEAR, 0, 0, NULL); if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { err(EXIT_FAILURE, "failed to register kevent"); } - EV_SET(&event, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); - if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { - err(EXIT_FAILURE, "failed to register kevent"); - } - - EV_SET(&event, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); - if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { - err(EXIT_FAILURE, "failed to register kevent"); - } - - EV_SET(&event, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); - if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { - err(EXIT_FAILURE, "failed to register kevent"); - } memset(&event, 0, sizeof(struct kevent)); /* Spawn a child to exec the command. */ @@ -492,11 +482,12 @@ daemon_eventloop(struct daemon_state *state) } continue; default: + assert(0 && "Unexpected kevent filter type"); continue; } } - close(kq); + /* EVFILT_READ kqueue filter goes away here. */ close(state->pipe_fd[0]); state->pipe_fd[0] = -1; @@ -510,19 +501,76 @@ daemon_eventloop(struct daemon_state *state) } } +/* + * Note that daemon_sleep() should not be called with anything but the signal + * events in the kqueue without further consideration. + */ static void daemon_sleep(struct daemon_state *state) { - struct timespec ts = { state->restart_delay, 0 }; + struct kevent event = { 0 }; + int ret; + + assert(state->pipe_fd[0] == -1); + assert(state->pipe_fd[1] == -1); if (!state->restart_enabled) { return; } - while (nanosleep(&ts, &ts) == -1) { - if (errno != EINTR) { - err(1, "nanosleep"); + + EV_SET(&event, 0, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, + state->restart_delay, NULL); + if (kevent(state->kqueue_fd, &event, 1, NULL, 0, NULL) == -1) { + err(1, "failed to register timer"); + } + + for (;;) { + ret = kevent(state->kqueue_fd, NULL, 0, &event, 1, NULL); + if (ret == -1) { + if (errno != EINTR) { + err(1, "kevent"); + } + + continue; + } + + /* + * Any other events being raised are indicative of a problem + * that we need to investigate. Most likely being that + * something was not cleaned up from the eventloop. + */ + assert(event.filter == EVFILT_TIMER || + event.filter == EVFILT_SIGNAL); + + if (event.filter == EVFILT_TIMER) { + /* Break's over, back to work. */ + break; + } + + /* Process any pending signals. */ + switch (event.ident) { + case SIGTERM: + /* + * We could disarm the timer, but we'll be terminating + * promptly anyways. + */ + state->restart_enabled = false; + return; + case SIGHUP: + if (state->log_reopen && state->output_fd >= 0) { + reopen_log(state); + } + + break; + case SIGCHLD: + default: + /* Discard */ + break; } } + + /* SIGTERM should've returned immediately. */ + assert(state->restart_enabled); } static void @@ -712,6 +760,7 @@ daemon_state_init(struct daemon_state *state) .restart_enabled = false, .pid = 0, .keep_cur_workdir = 1, + .kqueue_fd = -1, .restart_delay = 1, .stdmask = STDOUT_FILENO | STDERR_FILENO, .syslog_enabled = false, @@ -730,6 +779,9 @@ daemon_terminate(struct daemon_state *state) { assert(state != NULL); + if (state->kqueue_fd >= 0) { + close(state->kqueue_fd); + } if (state->output_fd >= 0) { close(state->output_fd); } @@ -800,6 +852,35 @@ daemon_set_child_pipe(struct daemon_state *state) close(state->pipe_fd[0]); } +static int +daemon_setup_kqueue(void) +{ + int kq; + struct kevent event = { 0 }; + + kq = kqueuex(KQUEUE_CLOEXEC); + if (kq == -1) { + err(EXIT_FAILURE, "kqueue"); + } + + EV_SET(&event, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { + err(EXIT_FAILURE, "failed to register kevent"); + } + + EV_SET(&event, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { + err(EXIT_FAILURE, "failed to register kevent"); + } + + EV_SET(&event, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); + if (kevent(kq, &event, 1, NULL, 0, NULL) == -1) { + err(EXIT_FAILURE, "failed to register kevent"); + } + + return (kq); +} + static int pidfile_truncate(struct pidfh *pfh) {