Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sh VFork()ing shell: From elric%netbsd.org@localhost:



details:   https://anonhg.NetBSD.org/src/rev/87b4114e0621
branches:  trunk
changeset: 537166:87b4114e0621
user:      christos <christos%NetBSD.org@localhost>
date:      Fri Sep 27 18:56:50 2002 +0000

description:
VFork()ing shell: From elric%netbsd.org@localhost:
Plus my changes:
        - walking process group fix in foregrounding a job.
        - reset of process group in parent shell if interrupted before the wait.
        - move INTON lower in the dowait so that the job structure is
          consistent.
        - error check all setpgid(), tcsetpgrp() calls.
        - eliminate unneeded strpgid() call.
        - check that we don't belong in the process group before we try to
          set it.

diffstat:

 bin/sh/eval.c  |   97 ++++++++++++++++++---
 bin/sh/exec.c  |   25 ++++-
 bin/sh/exec.h  |    4 +-
 bin/sh/input.c |   18 +++-
 bin/sh/input.h |    4 +-
 bin/sh/jobs.c  |  247 ++++++++++++++++++++++++++++++++++++--------------------
 bin/sh/jobs.h  |    4 +-
 bin/sh/main.c  |    6 +-
 bin/sh/redir.c |   16 ++-
 bin/sh/redir.h |    5 +-
 bin/sh/shell.h |   11 ++-
 bin/sh/trap.c  |   57 +++++++-----
 bin/sh/trap.h  |    8 +-
 bin/sh/var.c   |   14 +-
 bin/sh/var.h   |    4 +-
 15 files changed, 355 insertions(+), 165 deletions(-)

diffs (truncated from 1129 to 300 lines):

diff -r 2a74db8b973b -r 87b4114e0621 bin/sh/eval.c
--- a/bin/sh/eval.c     Fri Sep 27 18:38:53 2002 +0000
+++ b/bin/sh/eval.c     Fri Sep 27 18:56:50 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: eval.c,v 1.60 2002/09/27 17:37:12 mycroft Exp $        */
+/*     $NetBSD: eval.c,v 1.61 2002/09/27 18:56:50 christos Exp $       */
 
 /*-
  * Copyright (c) 1993
@@ -41,13 +41,16 @@
 #if 0
 static char sccsid[] = "@(#)eval.c     8.9 (Berkeley) 6/8/95";
 #else
-__RCSID("$NetBSD: eval.c,v 1.60 2002/09/27 17:37:12 mycroft Exp $");
+__RCSID("$NetBSD: eval.c,v 1.61 2002/09/27 18:56:50 christos Exp $");
 #endif
 #endif /* not lint */
 
 #include <signal.h>
 #include <unistd.h>
 
+#include <sys/types.h>
+#include <sys/wait.h>
+
 /*
  * Evaluate a command.
  */
@@ -587,6 +590,7 @@
 }
 
 
+int vforked = 0;
 
 /*
  * Execute a simple command.
@@ -626,6 +630,7 @@
        (void) &flags;
 #endif
 
+       vforked = 0;
        /* First expand the arguments. */
        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
        setstackmark(&smark);
@@ -728,7 +733,6 @@
            && (cmdentry.cmdtype != CMDBUILTIN
                 || cmdentry.u.index == DOTCMD
                 || cmdentry.u.index == EVALCMD))) {
-               INTOFF;
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
                if (flags & EV_BACKCMD) {
@@ -736,11 +740,73 @@
                        if (pipe(pip) < 0)
                                error("Pipe call failed");
                }
-               if (forkshell(jp, cmd, mode) != 0)
-                       goto parent;    /* at end of routine */
-               INTON;
+#ifdef DO_SHAREDVFORK
+               /* It is essential that if DO_SHAREDVFORK is defined that the
+                * child's address space is actually shared with the parent as
+                * we rely on this.
+                */
+               if (cmdentry.cmdtype == CMDNORMAL) {
+                       pid_t   pid;
+
+                       INTOFF;
+                       savelocalvars = localvars;
+                       localvars = NULL;
+                       for (sp = varlist.list ; sp ; sp = sp->next)
+                               mklocal(sp->text, VEXPORT);
+                       vforked = 1;
+                       switch (pid = vfork()) {
+                       case -1:
+                               TRACE(("Vfork failed, errno=%d", errno));
+                               INTON;
+                               error("Cannot vfork");
+                               break;
+                       case 0:
+                               /* Make sure that exceptions only unwind to
+                                * after the vfork(2)
+                                */
+                               if (setjmp(jmploc.loc)) {
+                                       if (exception == EXSHELLPROC) {
+                                               /* We can't progress with the vfork,
+                                                * so, set vforked = 2 so the parent
+                                                * knows, and _exit();
+                                                */
+                                               vforked = 2;
+                                               _exit(0);
+                                       } else {
+                                               _exit(exerrno);
+                                       }
+                               }
+                               savehandler = handler;
+                               handler = &jmploc;
+                               forkchild(jp, cmd, mode, vforked);
+                               break;
+                       default:
+                               handler = savehandler;  /* restore from vfork(2) */
+                               poplocalvars();
+                               localvars = savelocalvars;
+                               if (vforked == 2) {
+                                       vforked = 0;
+
+                                       (void)waitpid(pid, NULL, 0);
+                                       /* We need to progress in a normal fork fashion */
+                                       goto normal_fork;
+                               }
+                               vforked = 0;
+                               forkparent(jp, cmd, mode, pid);
+                               goto parent;
+                       }
+               } else {
+normal_fork:
+#endif
+                       if (forkshell(jp, cmd, mode) != 0)
+                               goto parent;    /* at end of routine */
+#ifdef DO_SHAREDVFORK
+               }
+#endif
                if (flags & EV_BACKCMD) {
-                       FORCEINTON;
+                       if (!vforked) {
+                               FORCEINTON;
+                       }
                        close(pip[0]);
                        if (pip[1] != 1) {
                                close(1);
@@ -784,7 +850,7 @@
                savehandler = handler;
                handler = &jmploc;
                for (sp = varlist.list ; sp ; sp = sp->next)
-                       mklocal(sp->text);
+                       mklocal(sp->text, 0);
                funcnest++;
                evaltree(cmdentry.u.func, flags & EV_TESTED);
                funcnest--;
@@ -863,12 +929,13 @@
 #ifdef DEBUG
                trputs("normal command:  ");  trargs(argv);
 #endif
-               clearredir();
-               redirect(cmd->ncmd.redirect, 0);
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       setvareq(sp->text, VEXPORT|VSTACK);
+               clearredir(vforked);
+               redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0);
+               if (!vforked)
+                       for (sp = varlist.list ; sp ; sp = sp->next)
+                               setvareq(sp->text, VEXPORT|VSTACK);
                envp = environment();
-               shellexec(argv, envp, pathval(), cmdentry.u.index);
+               shellexec(argv, envp, pathval(), cmdentry.u.index, vforked);
        }
        goto out;
 
@@ -880,7 +947,6 @@
                close(pip[1]);
                backcmd->jp = jp;
        }
-       INTON;
 
 out:
        if (lastarg)
@@ -892,7 +958,6 @@
 }
 
 
-
 /*
  * Search for a command.  This is called before we fork so that the
  * location of the command will be available in the parent as well as
@@ -1022,7 +1087,7 @@
                optschanged();
                for (sp = cmdenviron; sp ; sp = sp->next)
                        setvareq(sp->text, VEXPORT|VSTACK);
-               shellexec(argv + 1, environment(), pathval(), 0);
+               shellexec(argv + 1, environment(), pathval(), 0, 0);
        }
        return 0;
 }
diff -r 2a74db8b973b -r 87b4114e0621 bin/sh/exec.c
--- a/bin/sh/exec.c     Fri Sep 27 18:38:53 2002 +0000
+++ b/bin/sh/exec.c     Fri Sep 27 18:56:50 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $       */
+/*     $NetBSD: exec.c,v 1.33 2002/09/27 18:56:50 christos Exp $       */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -41,15 +41,17 @@
 #if 0
 static char sccsid[] = "@(#)exec.c     8.4 (Berkeley) 6/8/95";
 #else
-__RCSID("$NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $");
+__RCSID("$NetBSD: exec.c,v 1.33 2002/09/27 18:56:50 christos Exp $");
 #endif
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 
 /*
@@ -102,7 +104,7 @@
 int exerrno = 0;                       /* Last exec error */
 
 
-STATIC void tryexec __P((char *, char **, char **));
+STATIC void tryexec __P((char *, char **, char **, int));
 STATIC void execinterp __P((char **, char **));
 STATIC void printentry __P((struct tblentry *, int));
 STATIC void clearcmdentry __P((int));
@@ -118,22 +120,23 @@
  */
 
 void
-shellexec(argv, envp, path, idx)
+shellexec(argv, envp, path, idx, vforked)
        char **argv, **envp;
        const char *path;
        int idx;
+       int vforked;
 {
        char *cmdname;
        int e;
 
        if (strchr(argv[0], '/') != NULL) {
-               tryexec(argv[0], argv, envp);
+               tryexec(argv[0], argv, envp, vforked);
                e = errno;
        } else {
                e = ENOENT;
                while ((cmdname = padvance(&path, argv[0])) != NULL) {
                        if (--idx < 0 && pathopt == NULL) {
-                               tryexec(cmdname, argv, envp);
+                               tryexec(cmdname, argv, envp, vforked);
                                if (errno != ENOENT && errno != ENOTDIR)
                                        e = errno;
                        }
@@ -159,10 +162,11 @@
 
 
 STATIC void
-tryexec(cmd, argv, envp)
+tryexec(cmd, argv, envp, vforked)
        char *cmd;
        char **argv;
        char **envp;
+       int vforked;
        {
        int e;
 #ifndef BSD
@@ -178,6 +182,13 @@
 #endif
        e = errno;
        if (e == ENOEXEC) {
+               if (vforked) {
+                       /* We are currently vfork(2)ed, so raise an
+                        * exception, and evalcommand will try again
+                        * with a normal fork(2).
+                        */
+                       exraise(EXSHELLPROC);
+               }
                initshellproc();
                setinputfile(cmd, 0);
                commandname = arg0 = savestr(argv[0]);
diff -r 2a74db8b973b -r 87b4114e0621 bin/sh/exec.h
--- a/bin/sh/exec.h     Fri Sep 27 18:38:53 2002 +0000
+++ b/bin/sh/exec.h     Fri Sep 27 18:56:50 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: exec.h,v 1.17 2000/05/22 10:18:47 elric Exp $  */
+/*     $NetBSD: exec.h,v 1.18 2002/09/27 18:56:51 christos Exp $       */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -60,7 +60,7 @@
 extern const char *pathopt;    /* set by padvance */
 extern int exerrno;            /* last exec error */
 
-void shellexec __P((char **, char **, const char *, int))
+void shellexec __P((char **, char **, const char *, int, int))
     __attribute__((noreturn));
 char *padvance __P((const char **, const char *));
 int hashcmd __P((int, char **));
diff -r 2a74db8b973b -r 87b4114e0621 bin/sh/input.c
--- a/bin/sh/input.c    Fri Sep 27 18:38:53 2002 +0000
+++ b/bin/sh/input.c    Fri Sep 27 18:56:50 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: input.c,v 1.35 2001/02/04 19:52:06 christos Exp $      */
+/*     $NetBSD: input.c,v 1.36 2002/09/27 18:56:52 christos Exp $      */
 
 /*-
  * Copyright (c) 1991, 1993



Home | Main Index | Thread Index | Old Index