Re: Looking at "int vforked" in signal handler is racy
Harald van Dijk <[email protected]> Fri, 22 Aug 2025 02:32:54 +0100
| Newsgroups | org.kernel.vger.dash |
|---|---|
| Message-ID | <[email protected]> |
On 11/08/2025 13:58, Harald van Dijk wrote: > On 11/08/2025 06:00, Herbert Xu wrote: >> On Sun, Aug 10, 2025 at 11:20:40PM +0100, Harald van Dijk wrote: >>> >>> That approach seems solid to me at a very quick glance. I think you >>> don't >>> even need separate have_vfork_sibling and vfork_parent_pid variables, >>> just >>> make the existing vforked variable a pid, or 0. A mostly untested patch >>> using that: >> >> Looks good to me. Could you turn this into a patch please? If >> you could run some quick speed tests on this versus the existing >> code that would be even better :) > > It will be a little while before I can do meaningful measurements, but I > will do so when I can. The impact on config.status --recheck, measured by running it 100 times with the patch, 100 times without, and averaging the run times, reveals that the impact is so low it is lost in the noise, and not even clear it is beneficial. One attempt showed an average of 2.225s without the patch, 2.221s with the patch. Doing the exact same measurements again showed an average of 2.221s without the patch, 2.223s with the patch. The build was using clang 19.1.7 on x86_64, no special compiler flags, just -O2. The patch that I tested is attached. I welcome anyone doing their own measurements using better benchmarks to see if they can determine whether this patch is useful. Cheers, Harald van Dijk
0001-jobs-avoid-blocking-signals-on-vfork.patch
(text/x-patch, 1.2 KB)
From a112e6581540bf7d34bb2f47042e8927bcd95d0d Mon Sep 17 00:00:00 2001 From: Harald van Dijk <[email protected]> Date: Fri, 22 Aug 2025 02:05:14 +0100 Subject: [PATCH] jobs: avoid blocking signals on vfork(). As pointed out by Denys Vlasenko, we can avoid blocking signals on vfork() by making the signal handler of a vfork child immediately return. This saves a syscall. --- src/jobs.c | 5 +---- src/trap.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/jobs.c b/src/jobs.c index 51e6fa1..83d9694 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -991,20 +991,17 @@ struct job *vforkexec(union node *n, char **argv, const char *path, int idx) jp = makejob(1); - sigblockall(NULL); - vforked++; + vforked = getpid(); pid = vfork(); if (!pid) { forkchild(jp, n, FORK_FG); - sigclearmask(); shellexec(argv, path, idx); /* NOTREACHED */ } vforked = 0; - sigclearmask(); forkparent(jp, n, FORK_FG, pid); return jp; diff --git a/src/trap.c b/src/trap.c index aebffa0..23829a5 100644 --- a/src/trap.c +++ b/src/trap.c @@ -312,7 +312,7 @@ ignoresig(int signo) void onsig(int signo) { - if (vforked) + if (vforked && getpid() != vforked) return; if (signo == SIGCHLD) { -- 2.47.2