svn commit: r249242 - stable/9/bin/sh
Jilles Tjoelker
jilles at FreeBSD.org
Sun Apr 7 21:25:15 UTC 2013
Author: jilles
Date: Sun Apr 7 21:25:14 2013
New Revision: 249242
URL: http://svnweb.freebsd.org/changeset/base/249242
Log:
MFC r230998,r233792: 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.
Various incarnations of this patch have been shown to bring performance
improvements:
http://lists.freebsd.org/pipermail/freebsd-hackers/2012-January/037581.html
The use of vfork() can be disabled by setting a variable named
SH_DISABLE_VFORK.
Modified:
stable/9/bin/sh/eval.c
stable/9/bin/sh/jobs.c
stable/9/bin/sh/jobs.h
stable/9/bin/sh/var.c
stable/9/bin/sh/var.h
Directory Properties:
stable/9/bin/sh/ (props changed)
Modified: stable/9/bin/sh/eval.c
==============================================================================
--- stable/9/bin/sh/eval.c Sun Apr 7 17:54:38 2013 (r249241)
+++ stable/9/bin/sh/eval.c Sun Apr 7 21:25:14 2013 (r249242)
@@ -906,6 +906,15 @@ evalcommand(union node *cmd, int flags,
if (pipe(pip) < 0)
error("Pipe call failed: %s", strerror(errno));
}
+ if (cmdentry.cmdtype == CMDNORMAL &&
+ cmd->ncmd.redirect == NULL &&
+ varlist.list == NULL &&
+ (mode == FORK_FG || mode == FORK_NOJOB) &&
+ !disvforkset() && !iflag && !mflag) {
+ vforkexecshell(jp, argv, environment(), path,
+ cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
+ goto parent;
+ }
if (forkshell(jp, cmd, mode) != 0)
goto parent; /* at end of routine */
if (flags & EV_BACKCMD) {
Modified: stable/9/bin/sh/jobs.c
==============================================================================
--- stable/9/bin/sh/jobs.c Sun Apr 7 17:54:38 2013 (r249241)
+++ stable/9/bin/sh/jobs.c Sun Apr 7 21:25:14 2013 (r249242)
@@ -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"
@@ -884,6 +885,54 @@ forkshell(struct job *jp, union node *n,
}
+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, %s, %p) called\n", jp - jobtab, argv[0],
+ (void *)pip));
+ 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.
Modified: stable/9/bin/sh/jobs.h
==============================================================================
--- stable/9/bin/sh/jobs.h Sun Apr 7 17:54:38 2013 (r249241)
+++ stable/9/bin/sh/jobs.h Sun Apr 7 21:25:14 2013 (r249242)
@@ -91,6 +91,7 @@ void setjobctl(int);
void showjobs(int, int);
struct job *makejob(union node *, int);
pid_t forkshell(struct job *, union node *, int);
+pid_t vforkexecshell(struct job *, char **, char **, const char *, int, int []);
int waitforjob(struct job *, int *);
int stoppedjobs(void);
int backgndpidset(void);
Modified: stable/9/bin/sh/var.c
==============================================================================
--- stable/9/bin/sh/var.c Sun Apr 7 17:54:38 2013 (r249241)
+++ stable/9/bin/sh/var.c Sun Apr 7 21:25:14 2013 (r249242)
@@ -94,6 +94,7 @@ struct var vps2;
struct var vps4;
struct var vvers;
static struct var voptind;
+struct var vdisvfork;
int forcelocal;
@@ -125,6 +126,8 @@ static const struct varinit varinit[] =
#endif
{ &voptind, 0, "OPTIND=1",
getoptsreset },
+ { &vdisvfork, VUNSET, "SH_DISABLE_VFORK=",
+ NULL },
{ NULL, 0, NULL,
NULL }
};
Modified: stable/9/bin/sh/var.h
==============================================================================
--- stable/9/bin/sh/var.h Sun Apr 7 17:54:38 2013 (r249241)
+++ stable/9/bin/sh/var.h Sun Apr 7 21:25:14 2013 (r249242)
@@ -79,6 +79,7 @@ extern struct var vppid;
extern struct var vps1;
extern struct var vps2;
extern struct var vps4;
+extern struct var vdisvfork;
#ifndef NO_HISTORY
extern struct var vhistsize;
extern struct var vterm;
@@ -109,6 +110,7 @@ extern int initial_localeisutf8;
#endif
#define mpathset() ((vmpath.flags & VUNSET) == 0)
+#define disvforkset() ((vdisvfork.flags & VUNSET) == 0)
void initvar(void);
void setvar(const char *, const char *, int);
More information about the svn-src-stable-9
mailing list