From nobody Wed Feb 25 21:12:53 2026 X-Original-To: dev-commits-src-main@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 4fLnP12yXZz6TnLy for ; Wed, 25 Feb 2026 21:12:53 +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 "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fLnP11stJz47Dq for ; Wed, 25 Feb 2026 21:12:53 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772053973; 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=AEUabYiJLEWqTEUEOVh3BfQTtfltTdSDlWBZtmYZh7M=; b=nf4uIlbpmGShVrmHbkvOy5PaIQS5Mq+zoTUjah5tc7swiTvGIDf67yoN7yu2EK4KhMvOa8 1q6D1QzNVoGm1HEssE/xrxrSPLsITd2zeqswrtyAc6ITd9B1pZ3cKomYgGJUF2NuBm8vaF 4j5j4+iBK1wlZ/ev0oShljbm3P/FVa1S/Oskct6HyeRpbyPNEk9V9jdptw7wLXQFq/Uplw VNx1Dox2BusrbFX2g0Sgsooo4U+L5cxdXn+6vYlMFAIRvKGPhmGf3njX1jvvQOUxuq5kUK 4Fu6L/hMu8OwdEu7ELVDuCbnd0OeIHmfEoxbliAtjd31V8u1aM9w35mEW3zB4w== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1772053973; a=rsa-sha256; cv=none; b=dwZNwrXd72V9pe04VJUMmxKYqHf+utxRA3P94qQZe4KaJIFy7Ujdr6st5dpp6ghJBtpIDJ MnyKJ6aVogovo4hqXl+X1d7uG4uI0yIrIW0CoetbxDXN/9f+qkW6yaPDItCeIPhzSy07fN 5LagH3Q/3RgGAiBgxLzjF+bt678kI6Q5DMIhadGngkf82/udLSD0IyeZRxsfeAUli+qXBw v2zyKu3FHeAkTxGIbJYThLvAZ0DV8kY9TnzUK7XC0bWwqc3b6mxj7eBz/T30T5dlsbXjXI 6ggWJ0Vr/Rd9rlIf7xcoGWvgkpKmkxwURXLcgMSKIjsFgKa1VqL3M5zV+AG2xQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772053973; 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=AEUabYiJLEWqTEUEOVh3BfQTtfltTdSDlWBZtmYZh7M=; b=LBTOZAsXo/BP9vDLagzAQ7R1dR0gfpNdf58MErOTSGc4OignmZnXpN961P5zQSS/9qNRmv 792xmdarFCl7fILcH4I3c+A8xDppvNASXm3uukH0lasqoDy+uXXww+c7hXCi0pOLpo8CTs hTiWtjLwxX+aw6Rtc2YFYv7zDV38kCCgXxwVDDP+t2vMKWOW8vP510fQQuZg2GWFDxyil7 WT3ZB624e+pZUfdYATvhxQYuf+uqXa0q/lbUubMf8dhWPAmC5srIIgrJo5XWEn3230yGxR oQvZuxSbWteNivp4Z+oorFuE2qW6sclgckxDujm28U021OpByMzLE/r/NOMS9w== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fLnP10hNVz1HCs for ; Wed, 25 Feb 2026 21:12:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 30816 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 25 Feb 2026 21:12:53 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav Subject: git: 6e589e6e8e64 - main - system(3): Improve signal handling List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 6e589e6e8e64793adb437c561ec084dbb6ad1ced Auto-Submitted: auto-generated Date: Wed, 25 Feb 2026 21:12:53 +0000 Message-Id: <699f65d5.30816.41b354e9@gitrepo.freebsd.org> The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=6e589e6e8e64793adb437c561ec084dbb6ad1ced commit 6e589e6e8e64793adb437c561ec084dbb6ad1ced Author: Dag-Erling Smørgrav AuthorDate: 2026-02-25 21:12:21 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2026-02-25 21:12:21 +0000 system(3): Improve signal handling Ignore SIGINT and SIGQUIT and block SIGCHLD, as POSIX requires. To deal with the concurrency problem described in POSIX, we keep track of the count of concurrent invocations. We ignore and block signals only when the counter was zero before we incremented it, and restore them only when the counter reaches zero after we decrement it. Note that this does not address the issue of thread cancellation. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: bnovkov, sef, kevans Differential Revision: https://reviews.freebsd.org/D55471 --- lib/libc/stdlib/system.c | 116 +++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c index b581a6ec3b14..17dd63eb52f9 100644 --- a/lib/libc/stdlib/system.c +++ b/lib/libc/stdlib/system.c @@ -32,21 +32,22 @@ #include "namespace.h" #include #include + +#include +#include #include -#include #include +#include #include #include -#include -#include #include "un-namespace.h" #include "libc_private.h" +#include "spinlock.h" #pragma weak system int system(const char *command) { - return (((int (*)(const char *)) __libc_interposing[INTERPOS_system])(command)); } @@ -54,54 +55,83 @@ system(const char *command) int __libc_system(const char *command) { - pid_t pid, savedpid; - int pstat; - struct sigaction ign, intact, quitact; - sigset_t newsigblock, oldsigblock; + static spinlock_t lock = _SPINLOCK_INITIALIZER; + static volatile unsigned long concurrent; + static struct sigaction ointact, oquitact; + struct sigaction ign; + sigset_t sigblock, osigblock; + int pstat = -1, serrno = 0; + pid_t pid; - if (!command) /* just checking... */ - return(1); + if (command == NULL) /* just checking... */ + return (1); - (void)sigemptyset(&newsigblock); - (void)sigaddset(&newsigblock, SIGCHLD); - (void)sigaddset(&newsigblock, SIGINT); - (void)sigaddset(&newsigblock, SIGQUIT); - (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); - switch(pid = vfork()) { /* - * In the child, use unwrapped syscalls. libthr is in - * undefined state after vfork(). + * If we are the first concurrent instance, ignore SIGINT and + * SIGQUIT. Block SIGCHLD regardless of concurrency, since on + * FreeBSD, sigprocmask() is equivalent to pthread_sigmask(). */ - case -1: /* error */ - (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - return (-1); - case 0: /* child */ + if (__isthreaded) + _SPINLOCK(&lock); + if (concurrent++ == 0) { + memset(&ign, 0, sizeof(ign)); + ign.sa_handler = SIG_IGN; + sigemptyset(&ign.sa_mask); + (void)__libc_sigaction(SIGINT, &ign, &ointact); + (void)__libc_sigaction(SIGQUIT, &ign, &oquitact); + } + sigemptyset(&sigblock); + sigaddset(&sigblock, SIGCHLD); + (void)__libc_sigprocmask(SIG_BLOCK, &sigblock, &osigblock); + if (__isthreaded) + _SPINUNLOCK(&lock); + + /* + * Fork the child process. + */ + if ((pid = fork()) < 0) { /* error */ + serrno = errno; + } else if (pid == 0) { /* child */ /* - * Restore original signal dispositions and exec the command. + * Restore original signal dispositions. */ - (void)__sys_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); + (void)__libc_sigaction(SIGINT, &ointact, NULL); + (void)__libc_sigaction(SIGQUIT, &oquitact, NULL); + (void)__sys_sigprocmask(SIG_SETMASK, &osigblock, NULL); + /* + * Exec the command. + */ + execl(_PATH_BSHELL, "sh", "-c", command, NULL); _exit(127); + } else { /* parent */ + /* + * Wait for the child to terminate. + */ + while (_wait4(pid, &pstat, 0, NULL) < 0) { + if (errno != EINTR) { + serrno = errno; + break; + } + } } - /* - * If we are running means that the child has either completed - * its execve, or has failed. - * Block SIGINT/QUIT because sh -c handles it and wait for - * it to clean up. + + /* + * If we are the last concurrent instance, restore original signal + * dispositions. Unblock SIGCHLD, unless it was already blocked. */ - memset(&ign, 0, sizeof(ign)); - ign.sa_handler = SIG_IGN; - (void)sigemptyset(&ign.sa_mask); - (void)__libc_sigaction(SIGINT, &ign, &intact); - (void)__libc_sigaction(SIGQUIT, &ign, &quitact); - savedpid = pid; - do { - pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0); - } while (pid == -1 && errno == EINTR); - (void)__libc_sigaction(SIGINT, &intact, NULL); - (void)__libc_sigaction(SIGQUIT, &quitact, NULL); - (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - return (pid == -1 ? -1 : pstat); + if (__isthreaded) + _SPINLOCK(&lock); + if (--concurrent == 0) { + (void)__libc_sigaction(SIGINT, &ointact, NULL); + (void)__libc_sigaction(SIGQUIT, &oquitact, NULL); + } + if (!sigismember(&osigblock, SIGCHLD)) + (void)__libc_sigprocmask(SIG_UNBLOCK, &sigblock, NULL); + if (__isthreaded) + _SPINUNLOCK(&lock); + if (serrno != 0) + errno = serrno; + return (pstat); } __weak_reference(__libc_system, __system);