From: "Carlo Marcelo Arenas Belón" <carenas@gmail.com>
To: git@vger.kernel.org
Cc: chris.torek@gmail.com, gitster@pobox.com,
phillip.wood123@gmail.com,
"Carlo Marcelo Arenas Belón" <carenas@gmail.com>
Subject: [RFC PATCH] daemon: add a self pipe to trigger reaping of children
Date: Thu, 26 Jun 2025 11:24:32 -0700 [thread overview]
Message-ID: <20250626182432.87523-1-carenas@gmail.com> (raw)
In-Reply-To: <c314cd2d-8fdd-4386-bda0-881ff87d9204@gmail.com>
There has always been a small race condition between the time a
children status is checked, and the arrival of a SIGCHLD that
would alert us of their demise, hopefully interrupt poll().
To close the gap, add the reading side of a pipe to the poll and
use the signal handler to write to it for each child.
Suggested=by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
---
Implements the "self pipe" trick Hillip suggested.
I tried to make self healing and optional, as I also presume the race
condition it is meant to address is very unlikely.
An obvious disadvantage (at least of this implementation), is that it
actually doubles the number of events that need to be handled for each
children process on most cases (ex: when `poll()` gets interrupted)
I suspect that if fixing that last race condition is so important with
the current foundation, it might be better to reintroduce some sort of
timeout to poll(), so that they will be cleared periodically.
I had a prototype (only the bare minimum) that I thought was more
efficient and that would instead remove completely the need for a
signal handler which I would post (only for RFC) later.
daemon.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/daemon.c b/daemon.c
index d1be61fd57..d3b9421575 100644
--- a/daemon.c
+++ b/daemon.c
@@ -912,14 +912,17 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
add_child(&cld, addr, addrlen);
}
-static void child_handler(int signo UNUSED)
+int poll_pipe[2] = { -1, -1 };
+
+static void child_handler(int signo)
{
/*
- * Otherwise empty handler because systemcalls will get interrupted
- * upon signal receipt
* SysV needs the handler to be rearmed
*/
signal(SIGCHLD, child_handler);
+
+ if (poll_pipe[1] >= 0)
+ write(poll_pipe[1], &signo, 1);
}
static int set_reuse_addr(int sockfd)
@@ -1121,20 +1124,43 @@ static void socksetup(struct string_list *listen_addr, int listen_port, struct s
static int service_loop(struct socketlist *socklist)
{
struct pollfd *pfd;
+ unsigned long nfds = 1 + socklist->nr;
+
+ ALLOC_ARRAY(pfd, nfds);
+ if (!pipe(poll_pipe)) {
+ for (int i = 0; i < 2; i++) {
+ int flags;
+
+ flags = fcntl(poll_pipe[i], F_GETFD, 0);
+ if (flags >= 0)
+ fcntl(poll_pipe[i], F_SETFD, flags | FD_CLOEXEC);
+
+ flags = fcntl(poll_pipe[i], F_GETFL, 0);
+ if (flags < 0 || fcntl(poll_pipe[i], F_SETFL,
+ flags | O_NONBLOCK) == -1) {
+ close(poll_pipe[0]);
+ close(poll_pipe[1]);
+ poll_pipe[0] = poll_pipe[1] = -1;
+ break;
+ }
+ }
+ }
+ pfd[0].fd = poll_pipe[0];
+ pfd[0].events = POLLIN;
- CALLOC_ARRAY(pfd, socklist->nr);
-
- for (size_t i = 0; i < socklist->nr; i++) {
- pfd[i].fd = socklist->list[i];
+ for (size_t i = 1; i < nfds; i++) {
+ pfd[i].fd = socklist->list[i - 1];
pfd[i].events = POLLIN;
}
signal(SIGCHLD, child_handler);
for (;;) {
+ int nevents, scratch;
+
check_dead_children();
- if (poll(pfd, socklist->nr, -1) < 0) {
+ if ((nevents = poll(pfd, nfds, -1)) <= 0) {
if (errno != EINTR) {
logerror("Poll failed, resuming: %s",
strerror(errno));
@@ -1143,7 +1169,17 @@ static int service_loop(struct socketlist *socklist)
continue;
}
- for (size_t i = 0; i < socklist->nr; i++) {
+ if ((pfd[0].revents & POLLIN) && pfd[0].fd != -1) {
+ if (nevents == 1 && read(pfd[0].fd, &scratch, 1) > 0)
+ continue;
+ else if (!read(pfd[0].fd, &scratch, 1)) {
+ close(pfd[0].fd);
+ pfd[0].fd = -1;
+ }
+ nevents--;
+ }
+
+ for (size_t i = 1; nevents && i < nfds; i++) {
if (pfd[i].revents & POLLIN) {
union {
struct sockaddr sa;
@@ -1165,6 +1201,7 @@ static int service_loop(struct socketlist *socklist)
}
}
handle(incoming, &ss.sa, sslen);
+ nevents--;
}
}
}
--
2.50.0.131.gcf6f63ea6b.dirty
next prev parent reply other threads:[~2025-06-26 18:24 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-24 14:08 [PATCH 0/3] daemon: explicitly allow EINTR during poll() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-24 14:08 ` [PATCH 1/3] compat/posix.h: track SA_RESTART fallback Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-24 15:34 ` Junio C Hamano
2025-06-24 16:28 ` Junio C Hamano
2025-06-24 14:08 ` [PATCH 2/3] daemon: use sigaction() to install child_handler() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-24 15:37 ` Junio C Hamano
2025-06-24 22:29 ` Carlo Marcelo Arenas Belón
2025-06-24 23:27 ` Chris Torek
2025-06-24 16:20 ` Junio C Hamano
2025-06-24 21:28 ` Carlo Marcelo Arenas Belón
2025-06-24 21:32 ` Junio C Hamano
2025-06-24 14:08 ` [PATCH 3/3] daemon: explicitly allow EINTR during poll() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-24 14:33 ` Carlo Marcelo Arenas Belón
2025-06-24 15:43 ` Junio C Hamano
2025-06-25 7:35 ` [PATCH v2 0/3] " Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-25 7:35 ` [PATCH v2 1/3] compat/posix.h: track SA_RESTART fallback Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-25 16:07 ` Junio C Hamano
2025-06-25 22:24 ` Carlo Marcelo Arenas Belón
2025-06-26 0:33 ` Junio C Hamano
2025-06-26 1:35 ` Carlo Marcelo Arenas Belón
2025-06-26 0:45 ` Junio C Hamano
2025-06-25 7:35 ` [PATCH v2 2/3] daemon: use sigaction() to install child_handler() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-25 16:06 ` Junio C Hamano
2025-06-25 16:22 ` Junio C Hamano
2025-06-25 7:35 ` [PATCH v2 3/3] daemon: explicitly allow EINTR during poll() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-25 16:11 ` Junio C Hamano
2025-06-25 8:39 ` [PATCH v2 0/3] " Phillip Wood
2025-06-25 16:24 ` Junio C Hamano
2025-06-25 19:35 ` Phillip Wood
2025-06-26 18:24 ` Carlo Marcelo Arenas Belón [this message]
2025-06-26 21:22 ` [RFC PATCH 0/2] daemon: tracking childs without signals Carlo Marcelo Arenas Belón
2025-06-26 21:22 ` [RFC PATCH 1/2] run-command: add a pipe() write end to childs Carlo Marcelo Arenas Belón
2025-06-26 21:22 ` [RFC PATCH 2/2] daemon: poor man's pidfd like POC Carlo Marcelo Arenas Belón
2025-06-27 8:38 ` [RFC PATCH] daemon: add a self pipe to trigger reaping of children Phillip Wood
2025-06-28 6:19 ` Carlo Marcelo Arenas Belón
2025-07-01 13:38 ` Phillip Wood
2025-06-30 15:16 ` Junio C Hamano
2025-06-25 16:07 ` [PATCH v2 0/3] daemon: explicitly allow EINTR during poll() Junio C Hamano
2025-06-26 8:50 ` Carlo Marcelo Arenas Belón
2025-06-26 8:53 ` [PATCH v3 0/4] " Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-26 8:53 ` [PATCH v3 1/4] compat/posix.h: track SA_RESTART fallback Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-27 1:41 ` Junio C Hamano
2025-06-26 8:53 ` [PATCH v3 2/4] compat/mingw: allow sigaction(SIGCHLD) Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-26 12:52 ` Phillip Wood
2025-06-26 13:15 ` Carlo Marcelo Arenas Belón
2025-06-26 13:56 ` Phillip Wood
2025-06-26 14:58 ` Carlo Marcelo Arenas Belón
2025-06-26 15:19 ` phillip.wood123
2025-06-26 20:09 ` Carlo Marcelo Arenas Belón
2025-07-09 14:13 ` Phillip Wood
2025-07-09 16:36 ` Carlo Marcelo Arenas Belón
2025-06-26 8:53 ` [PATCH v3 3/4] daemon: use sigaction() to install child_handler() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-26 13:11 ` Phillip Wood
2025-06-26 15:33 ` Junio C Hamano
2025-06-26 16:36 ` Carlo Marcelo Arenas Belón
2025-06-26 18:04 ` Phillip Wood
2025-07-07 22:14 ` Junio C Hamano
2025-06-26 8:53 ` [PATCH v3 4/4] daemon: explicitly allow EINTR during poll() Carlo Marcelo Arenas Belón via GitGitGadget
2025-06-26 13:14 ` Phillip Wood
2025-07-09 14:12 ` [PATCH v3 0/4] " Phillip Wood
2025-07-09 17:04 ` Carlo Marcelo Arenas Belón
2025-07-10 19:45 ` [PATCH v4 0/2] " Carlo Marcelo Arenas Belón via GitGitGadget
2025-07-10 19:45 ` [PATCH v4 1/2] compat/mingw: allow sigaction(SIGCHLD) Carlo Marcelo Arenas Belón via GitGitGadget
2025-07-10 21:38 ` Eric Sunshine
2025-07-10 19:45 ` [PATCH v4 2/2] daemon: use sigaction() to install child_handler() Carlo Marcelo Arenas Belón via GitGitGadget
2025-07-10 21:26 ` [PATCH v4 0/2] daemon: explicitly allow EINTR during poll() Junio C Hamano
2025-07-10 23:18 ` Carlo Arenas
2025-07-11 13:14 ` Phillip Wood
2025-07-14 21:52 ` Junio C Hamano
2025-07-15 9:29 ` Phillip Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250626182432.87523-1-carenas@gmail.com \
--to=carenas@gmail.com \
--cc=chris.torek@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=phillip.wood123@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).