From owner-freebsd-hackers@FreeBSD.ORG Mon Jul 30 10:24:10 2012 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5F5B01065670 for ; Mon, 30 Jul 2012 10:24:10 +0000 (UTC) (envelope-from jilles@stack.nl) Received: from mx1.stack.nl (relay04.stack.nl [IPv6:2001:610:1108:5010::107]) by mx1.freebsd.org (Postfix) with ESMTP id ED5158FC1A for ; Mon, 30 Jul 2012 10:24:09 +0000 (UTC) Received: from snail.stack.nl (snail.stack.nl [IPv6:2001:610:1108:5010::131]) by mx1.stack.nl (Postfix) with ESMTP id 89C601DD4FB for ; Mon, 30 Jul 2012 12:24:08 +0200 (CEST) Received: by snail.stack.nl (Postfix, from userid 1677) id 72BB52847B; Mon, 30 Jul 2012 12:24:08 +0200 (CEST) Date: Mon, 30 Jul 2012 12:24:08 +0200 From: Jilles Tjoelker To: freebsd-hackers@freebsd.org Message-ID: <20120730102408.GA19983@stack.nl> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Subject: system() using vfork() or posix_spawn() X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Jul 2012 10:24:10 -0000 People sometimes use system() from large address spaces where it would improve performance greatly to use vfork() instead of fork(). A simple approach is to change fork() to vfork(), although I have not tried this. It seems safe enough to use sigaction and sigprocmask system calls in the vforked process. Alternatively, we can have posix_spawn() do the vfork() with signal changes. This avoids possible whining from compilers and static analyzers about using vfork() in system.c. However, I do not like the tricky code for signals and that it adds lines of code. This is lightly tested. Index: lib/libc/stdlib/system.c =================================================================== --- lib/libc/stdlib/system.c (revision 238371) +++ lib/libc/stdlib/system.c (working copy) @@ -42,16 +42,21 @@ #include #include #include +#include #include "un-namespace.h" #include "libc_private.h" +extern char **environ; + int __system(const char *command) { pid_t pid, savedpid; - int pstat; + int error, pstat; struct sigaction ign, intact, quitact; - sigset_t newsigblock, oldsigblock; + sigset_t newsigblock, oldsigblock, defmask; + const char *argv[4]; + posix_spawnattr_t attr; if (!command) /* just checking... */ return(1); @@ -65,28 +70,36 @@ ign.sa_flags = 0; (void)_sigaction(SIGINT, &ign, &intact); (void)_sigaction(SIGQUIT, &ign, &quitact); + (void)sigemptyset(&defmask); + if ((intact.sa_flags & SA_SIGINFO) != 0 || + intact.sa_handler != SIG_IGN) + (void)sigaddset(&defmask, SIGINT); + if ((quitact.sa_flags & SA_SIGINFO) != 0 || + quitact.sa_handler != SIG_IGN) + (void)sigaddset(&defmask, SIGQUIT); (void)sigemptyset(&newsigblock); (void)sigaddset(&newsigblock, SIGCHLD); (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); - switch(pid = fork()) { - case -1: /* error */ - break; - case 0: /* child */ - /* - * Restore original signal dispositions and exec the command. - */ - (void)_sigaction(SIGINT, &intact, NULL); - (void)_sigaction(SIGQUIT, &quitact, NULL); - (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); - execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); - _exit(127); - default: /* parent */ + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = command; + argv[3] = NULL; + if ((error = posix_spawnattr_init(&attr)) != 0 || + (error = posix_spawnattr_setsigmask(&attr, &oldsigblock)) != 0 || + (error = posix_spawnattr_setsigdefault(&attr, &defmask)) != 0 || + (error = posix_spawnattr_setflags(&attr, + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK)) != 0 || + (error = posix_spawn(&pid, _PATH_BSHELL, NULL, &attr, + __DECONST(char **, argv), environ)) != 0) { + pid = -1; + errno = error; + } else { savedpid = pid; do { pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0); } while (pid == -1 && errno == EINTR); - break; } + posix_spawnattr_destroy(&attr); (void)_sigaction(SIGINT, &intact, NULL); (void)_sigaction(SIGQUIT, &quitact, NULL); (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); -- Jilles Tjoelker