performance
[unix-history] / usr / src / bin / csh / exec.c
index c15bb07..b72c256 100644 (file)
@@ -1,4 +1,6 @@
-static char *sccsid = "@(#)exec.c 4.9 %G%";
+#ifndef lint
+static char *sccsid = "@(#)exec.c      4.10 (Berkeley) %G%";
+#endif
 
 #include "sh.h"
 #include <sys/dir.h>
 
 #include "sh.h"
 #include <sys/dir.h>
@@ -25,16 +27,25 @@ char        *exerr;                 /* Execution error message */
 char   *expath;                /* Path for exerr */
 
 /*
 char   *expath;                /* Path for exerr */
 
 /*
- * Xhash is an array of HSHSIZ chars, which are used to hash execs.
- * If it is allocated, then to tell whether ``name'' is (possibly)
- * present in the i'th component of the variable path, you look at
- * the i'th bit of xhash[hash("name")].  This is setup automatically
+ * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
+ * to hash execs.  If it is allocated (havhash true), then to tell
+ * whether ``name'' is (possibly) present in the i'th component
+ * of the variable path, you look at the bit in xhash indexed by
+ * hash(hashname("name"), i).  This is setup automatically
  * after .login is executed, and recomputed whenever ``path'' is
  * changed.
  * after .login is executed, and recomputed whenever ``path'' is
  * changed.
+ * The two part hash function is designed to let texec() call the
+ * more expensive hashname() only once and the simple hash() several
+ * times (once for each path component checked).
+ * Byte size is assumed to be 8.
  */
  */
-int    havhash;
-#define        HSHSIZ  511
-char   xhash[HSHSIZ];
+#define        HSHSIZ          8192                    /* 1k bytes */
+#define HSHMASK                (HSHSIZ - 1)
+#define HSHMUL         243
+char   xhash[HSHSIZ / 8];
+#define hash(a, b)     ((a) * HSHMUL + (b) & HSHMASK)
+#define bit(h, b)      ((h)[(b) >> 3] & 1 << ((b) & 7))        /* bit test */
+#define bis(h, b)      ((h)[(b) >> 3] |= 1 << ((b) & 7))       /* bit set */
 #ifdef VFORK
 int    hits, misses;
 #endif
 #ifdef VFORK
 int    hits, misses;
 #endif
@@ -49,7 +60,7 @@ doexec(t)
        register char *dp, **pv, **av;
        register struct varent *v;
        bool slash = any('/', t->t_dcom[0]);
        register char *dp, **pv, **av;
        register struct varent *v;
        bool slash = any('/', t->t_dcom[0]);
-       int hashval, i;
+       int hashval, hashval1, i;
        char *blk[2];
 
        /*
        char *blk[2];
 
        /*
@@ -72,7 +83,7 @@ doexec(t)
         * Otherwise trim off the quote bits.
         */
        gflag = 0; av = &t->t_dcom[1];
         * Otherwise trim off the quote bits.
         */
        gflag = 0; av = &t->t_dcom[1];
-       rscan(av, tglob);
+       tglob(av);
        if (gflag) {
                av = glob(av);
                if (av == 0)
        if (gflag) {
                av = glob(av);
                if (av == 0)
@@ -84,19 +95,21 @@ doexec(t)
 #ifdef VFORK
        Vav = av;
 #endif
 #ifdef VFORK
        Vav = av;
 #endif
-       scan(av, trim);
+       trim(av);
 
        xechoit(av);            /* Echo command if -x */
 
        xechoit(av);            /* Echo command if -x */
-       closech();              /* Close random fd's */
+       /*
+        * Since all internal file descriptors are set to close on exec,
+        * we don't need to close them explicitly here.  Just reorient
+        * ourselves for error messages.
+        */
+       SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
 
        /*
         * We must do this AFTER any possible forking (like `foo`
         * in glob) so that this shell can still do subprocesses.
         */
 
        /*
         * We must do this AFTER any possible forking (like `foo`
         * in glob) so that this shell can still do subprocesses.
         */
-#ifdef notdef
-       sigsys(SIGCHLD, SIG_IGN);       /* sigsys for vforks sake */
-#endif
-       sigsetmask(0);
+       (void) sigsetmask(0);
 
        /*
         * If no path, no words in path, or a / in the filename
 
        /*
         * If no path, no words in path, or a / in the filename
@@ -111,14 +124,17 @@ doexec(t)
        Vsav = sav;
 #endif
        if (havhash)
        Vsav = sav;
 #endif
        if (havhash)
-               hashval = xhash[hash(*av)];
+               hashval = hashname(*av);
        i = 0;
 #ifdef VFORK
        hits++;
 #endif
        do {
        i = 0;
 #ifdef VFORK
        hits++;
 #endif
        do {
-               if (!slash && pv[0][0] == '/' && havhash && (hashval & (1 << (i % 8))) == 0)
-                       goto cont;
+               if (!slash && pv[0][0] == '/' && havhash) {
+                       hashval1 = hash(hashval, i);
+                       if (!bit(xhash, hashval1))
+                               goto cont;
+               }
                if (pv[0][0] == 0 || eq(pv[0], "."))    /* don't make ./xxx */
                        texec(*av, av);
                else {
                if (pv[0][0] == 0 || eq(pv[0], "."))    /* don't make ./xxx */
                        texec(*av, av);
                else {
@@ -147,7 +163,7 @@ cont:
        Vav = 0;
 #endif
        xfree(sav);
        Vav = 0;
 #endif
        xfree(sav);
-       xfree(av);
+       xfree((char *)av);
        pexerr();
 }
 
        pexerr();
 }
 
@@ -162,9 +178,6 @@ pexerr()
        bferr("Command not found");
 }
 
        bferr("Command not found");
 }
 
-/* Last resort shell */
-char   *lastsh[] =     { SHELLPATH, 0 };
-
 /*
  * Execute command f, arg list t.
  * Record error message if not found.
 /*
  * Execute command f, arg list t.
  * Record error message if not found.
@@ -177,6 +190,7 @@ texec(f, t)
        register struct varent *v;
        register char **vp;
        extern char *sys_errlist[];
        register struct varent *v;
        register char **vp;
        extern char *sys_errlist[];
+       char *lastsh[2];
 
        execv(f, t);
        switch (errno) {
 
        execv(f, t);
        switch (errno) {
@@ -200,7 +214,7 @@ texec(f, t)
 #ifdef OTHERSH
                        if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
                                vp[0] = OTHERSH;
 #ifdef OTHERSH
                        if (ff != -1 && read(ff, &ch, 1) == 1 && ch != '#')
                                vp[0] = OTHERSH;
-                       close(ff);
+                       (void) close(ff);
 #endif
                } else
                        vp = v->vec;
 #endif
                } else
                        vp = v->vec;
@@ -225,15 +239,16 @@ texec(f, t)
        }
 }
 
        }
 }
 
+/*ARGSUSED*/
 execash(t, kp)
 execash(t, kp)
+       char **t;
        register struct command *kp;
 {
 
        register struct command *kp;
 {
 
-       didcch++;
        rechist();
        rechist();
-       signal(SIGINT, parintr);
-       signal(SIGQUIT, parintr);
-       signal(SIGTERM, parterm);               /* if doexec loses, screw */
+       (void) signal(SIGINT, parintr);
+       (void) signal(SIGQUIT, parintr);
+       (void) signal(SIGTERM, parterm);        /* if doexec loses, screw */
        lshift(kp->t_dcom, 1);
        exiterr++;
        doexec(kp);
        lshift(kp->t_dcom, 1);
        exiterr++;
        doexec(kp);
@@ -247,12 +262,14 @@ xechoit(t)
        if (adrof("echo")) {
                flush();
                haderr = 1;
        if (adrof("echo")) {
                flush();
                haderr = 1;
-               blkpr(t), printf("\n");
+               blkpr(t), putchar('\n');
                haderr = 0;
        }
 }
 
                haderr = 0;
        }
 }
 
-dohash()
+/*VARARGS0*//*ARGSUSED*/
+dohash(v)
+       char **v;
 {
        struct stat stb;
        DIR *dirp;
 {
        struct stat stb;
        DIR *dirp;
@@ -261,13 +278,14 @@ dohash()
        int i = 0;
        struct varent *v = adrof("path");
        char **pv;
        int i = 0;
        struct varent *v = adrof("path");
        char **pv;
+       int hashval;
 
        havhash = 1;
 
        havhash = 1;
-       for (cnt = 0; cnt < HSHSIZ; cnt++)
+       for (cnt = 0; cnt < sizeof xhash; cnt++)
                xhash[cnt] = 0;
        if (v == 0)
                return;
                xhash[cnt] = 0;
        if (v == 0)
                return;
-       for (pv = v->vec; *pv; pv++, i = (i + 1) % 8) {
+       for (pv = v->vec; *pv; pv++, i++) {
                if (pv[0][0] != '/')
                        continue;
                dirp = opendir(*pv);
                if (pv[0][0] != '/')
                        continue;
                dirp = opendir(*pv);
@@ -280,7 +298,12 @@ dohash()
                while ((dp = readdir(dirp)) != NULL) {
                        if (dp->d_ino == 0)
                                continue;
                while ((dp = readdir(dirp)) != NULL) {
                        if (dp->d_ino == 0)
                                continue;
-                       xhash[hash(dp->d_name)] |= (1 << i);
+                       if (dp->d_name[0] == '.' &&
+                           (dp->d_name[1] == '\0' ||
+                            dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
+                               continue;
+                       hashval = hash(hashname(dp->d_name), i);
+                       bis(xhash, hashval);
                }
                closedir(dirp);
        }
                }
                closedir(dirp);
        }
@@ -297,20 +320,20 @@ hashstat()
 {
 
        if (hits+misses)
 {
 
        if (hits+misses)
-       printf("%d hits, %d misses, %2d%%\n", hits, misses, 100 * hits / (hits + misses));
+               printf("%d hits, %d misses, %d%%\n",
+                       hits, misses, 100 * hits / (hits + misses));
 }
 #endif
 
 }
 #endif
 
-hash(cp)
+/*
+ * Hash a command name.
+ */
+hashname(cp)
        register char *cp;
 {
        register char *cp;
 {
-       register long hash = 0;
-       int retval;
+       register long h = 0;
 
        while (*cp)
 
        while (*cp)
-               hash += hash + *cp++;
-       if (hash < 0)
-               hash = -hash;
-       retval = hash % HSHSIZ;
-       return (retval);
+               h = hash(h, *cp++);
+       return ((int) h);
 }
 }