summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2013-08-13 20:38:55 +0000
committerpeter <peter@FreeBSD.org>2013-08-13 20:38:55 +0000
commit4fb136d7703ceb33fee815d56a074728cf18ea15 (patch)
treee44831d991b8830c5bc125a642dff83d910a90aa
parent90af9dfe1e2178ba3bfa458c93b026c996c1387c (diff)
downloadFreeBSD-src-4fb136d7703ceb33fee815d56a074728cf18ea15.zip
FreeBSD-src-4fb136d7703ceb33fee815d56a074728cf18ea15.tar.gz
vfork(2) was listed as deprecated in 1994 (r1573) and was the false
reports of its impending demise were removed in 2009 (r199257). However, in 1996 (r16117) system(3) was switched from vfork(2) to fork(2) based partly on this. Switch back to vfork(2). This has a dramatic effect in cases of extreme mmap use - such as excessive abuse (500+) of shared libraries. popen(3) has used vfork(2) for a while. vfork(2) isn't going anywhere.
-rw-r--r--lib/libc/stdlib/system.c38
1 files changed, 19 insertions, 19 deletions
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
index b552a63..64a5447 100644
--- a/lib/libc/stdlib/system.c
+++ b/lib/libc/stdlib/system.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
+#include <string.h>
#include <unistd.h>
#include <paths.h>
#include <errno.h>
@@ -56,37 +57,36 @@ __system(const char *command)
if (!command) /* just checking... */
return(1);
- /*
- * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
- * existing signal dispositions.
- */
- ign.sa_handler = SIG_IGN;
- (void)sigemptyset(&ign.sa_mask);
- ign.sa_flags = 0;
- (void)_sigaction(SIGINT, &ign, &intact);
- (void)_sigaction(SIGQUIT, &ign, &quitact);
(void)sigemptyset(&newsigblock);
(void)sigaddset(&newsigblock, SIGCHLD);
(void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
- switch(pid = fork()) {
+ switch(pid = vfork()) {
case -1: /* error */
- break;
+ (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ return (-1);
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 */
- savedpid = pid;
- do {
- pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
- } while (pid == -1 && errno == EINTR);
- 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.
+ */
+ memset(&ign, 0, sizeof(ign));
+ ign.sa_handler = SIG_IGN;
+ (void)sigemptyset(&ign.sa_mask);
+ (void)_sigaction(SIGINT, &ign, &intact);
+ (void)_sigaction(SIGQUIT, &ign, &quitact);
+ savedpid = pid;
+ do {
+ pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
+ } while (pid == -1 && errno == EINTR);
(void)_sigaction(SIGINT, &intact, NULL);
(void)_sigaction(SIGQUIT, &quitact, NULL);
(void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
OpenPOWER on IntegriCloud