summaryrefslogtreecommitdiffstats
path: root/bin/sh/jobs.c
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2012-02-04 23:12:14 +0000
committerjilles <jilles@FreeBSD.org>2012-02-04 23:12:14 +0000
commitc9a60ad55a7cdcf983430853a4bdb15d31340f0b (patch)
treecdf2aa0b0a8655054be3d8275658129bb9b75c99 /bin/sh/jobs.c
parenta3ada8a47cbcc2eecf9773251384c95d920c9cab (diff)
downloadFreeBSD-src-c9a60ad55a7cdcf983430853a4bdb15d31340f0b.zip
FreeBSD-src-c9a60ad55a7cdcf983430853a4bdb15d31340f0b.tar.gz
sh: Use vfork in a few common cases.
This uses vfork() for simple commands and command substitutions containing a single simple command, invoking an external program under certain conditions (no redirections or variable assignments, non-interactive shell, no job control). These restrictions limit the amount of code executed in a vforked child. There is a large speedup (for example 35%) in microbenchmarks. The difference in buildkernel is smaller (for example 0.5%) but still statistically significant. See http://lists.freebsd.org/pipermail/freebsd-hackers/2012-January/037581.html for some numbers. The use of vfork() can be disabled by setting a variable named SH_DISABLE_VFORK.
Diffstat (limited to 'bin/sh/jobs.c')
-rw-r--r--bin/sh/jobs.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c
index 232be8b..335d2ca 100644
--- a/bin/sh/jobs.c
+++ b/bin/sh/jobs.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
#undef CEOF /* syntax.h redefines this */
#endif
#include "redir.h"
+#include "exec.h"
#include "show.h"
#include "main.h"
#include "parser.h"
@@ -885,6 +886,54 @@ forkshell(struct job *jp, union node *n, int mode)
}
+pid_t
+vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
+{
+ pid_t pid;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+
+ TRACE(("vforkexecshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
+ mode));
+ INTOFF;
+ flushall();
+ savehandler = handler;
+ pid = vfork();
+ if (pid == -1) {
+ TRACE(("Vfork failed, errno=%d\n", errno));
+ INTON;
+ error("Cannot fork: %s", strerror(errno));
+ }
+ if (pid == 0) {
+ TRACE(("Child shell %d\n", (int)getpid()));
+ if (setjmp(jmploc.loc))
+ _exit(exception == EXEXEC ? exerrno : 2);
+ if (pip != NULL) {
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ }
+ handler = &jmploc;
+ shellexec(argv, envp, path, idx);
+ }
+ handler = savehandler;
+ if (jp) {
+ struct procstat *ps = &jp->ps[jp->nprocs++];
+ ps->pid = pid;
+ ps->status = -1;
+ ps->cmd = nullstr;
+ jp->foreground = 1;
+#if JOBS
+ setcurjob(jp);
+#endif
+ }
+ INTON;
+ TRACE(("In parent shell: child = %d\n", (int)pid));
+ return pid;
+}
+
/*
* Wait for job to finish.
OpenPOWER on IntegriCloud