aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2011-07-07 13:58:48 +0800
committerBen Hutchings <ben@decadent.org.uk>2020-03-28 21:10:37 +0000
commita99e81cedacbfaed18e580455969667f2320de5e (patch)
treecb0304f8b818ac8592599e0efaa01c37343a5324
parentdd7eb2c9e0faf742a9a2ce45629514c151348915 (diff)
downloadklibc-a99e81cedacbfaed18e580455969667f2320de5e.tar.gz
[klibc] dash: [SHELL] Optimize dash -c "command" to avoid a fork
[ dash commit ee5cbe9fd6bc02f31b4d955606288de36c3d4eab ] On Sun, Apr 10, 2011 at 07:36:49AM +0000, Jonathan Nieder wrote: > From: Jilles Tjoelker <jilles@stack.nl> > Date: Sat, 13 Jun 2009 16:17:45 -0500 > > This change only affects strings passed to -c, when the -s option is > not used. > > Use the EV_EXIT flag to inform the eval machinery that the string > being passed is the entirety of input. This way, a fork may be > omitted in many special cases. > > If there are empty lines after the last command, the evalcmd will not > see the end early enough and forks will not be omitted. The same thing > seems to happen in bash. > > Example: > sh -c 'ps lT' > No longer shows a shell process waiting for ps to finish. > > [jn: ported from FreeBSD SVN r194128. Bugs are mine.] > > Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Instead of detecting EOF using the input layer, I'm going to use the parser instead. In either case, we always have to read ahead in order to complete the parsing of the previous node. Therefore we always know whether there is more to come, except in the case where we see a newline/semicolon or similar. For the purposes of sh -c, this should be sufficient. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> [bwh: Update usr/dash/Kbuild for mktokens and parser.h changes, and README.dash to reflect that we now have this change] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--usr/dash/.gitignore1
-rw-r--r--usr/dash/Kbuild10
-rw-r--r--usr/dash/README.dash3
-rw-r--r--usr/dash/eval.c6
-rw-r--r--usr/dash/eval.h4
-rw-r--r--usr/dash/main.c2
-rw-r--r--usr/dash/mktokens9
-rw-r--r--usr/dash/parser.c5
-rw-r--r--usr/dash/parser.h8
9 files changed, 33 insertions, 15 deletions
diff --git a/usr/dash/.gitignore b/usr/dash/.gitignore
index 480952fe083a7..16a0cce9c0770 100644
--- a/usr/dash/.gitignore
+++ b/usr/dash/.gitignore
@@ -11,3 +11,4 @@ sh
sh.shared
syntax.[ch]
token.h
+token_vars.h
diff --git a/usr/dash/Kbuild b/usr/dash/Kbuild
index 23809a3af6b9d..f9c0b2870a9af 100644
--- a/usr/dash/Kbuild
+++ b/usr/dash/Kbuild
@@ -35,13 +35,19 @@ targets := static/sh static/sh.g shared/sh shared/sh.g $(gen-o-files)
# explicit dependency for all generated files
$(addprefix $(obj)/, $(static/sh-y)): $(addprefix $(obj)/, $(gen-h-files))
-# Generate token.h
-targets += token.h
+$(obj)/mksyntax: $(obj)/token.h
+
+# Generate token{,_vars}.h
+targets += token.h token_vars.h
quiet_cmd_mktokens = GEN $@
cmd_mktokens = (cd $(obj) && sh $(srctree)/$(src)/mktokens)
$(obj)/token.h: $(src)/mktokens
$(call if_changed,mktokens)
+# side effect..
+$(obj)/token_vars.h: $(obj)/token.h
+ $(Q):
+
# Generate builtins.def
targets += builtins.def
quiet_cmd_mkbuiltins_def = GEN $@
diff --git a/usr/dash/README.dash b/usr/dash/README.dash
index f45d28bef62d5..3bb72799a9e85 100644
--- a/usr/dash/README.dash
+++ b/usr/dash/README.dash
@@ -2,8 +2,7 @@ This version of dash was obtained from
git://git.kernel.org/pub/scm/utils/dash/dash.git
-It corresponds up to changeset 46abc8c6d8a5e9a5712bdc1312c0b6960eec65a4
-omitting ee5cbe9fd6bc02f31b4d955606288de36c3d4eab.
+It corresponds up to changeset 46abc8c6d8a5e9a5712bdc1312c0b6960eec65a4.
Several changes have been made for klibc:
diff --git a/usr/dash/eval.c b/usr/dash/eval.c
index dd144948a9fa8..e6f6cd5c28508 100644
--- a/usr/dash/eval.c
+++ b/usr/dash/eval.c
@@ -65,10 +65,6 @@
#endif
-/* flags in argument to evaltree */
-#define EV_EXIT 01 /* exit after evaluating tree */
-#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
-
int evalskip; /* set if we are skipping commands */
STATIC int skipcount; /* number of levels to skip */
MKINIT int loopnest; /* current loop nesting level */
@@ -169,7 +165,7 @@ evalstring(char *s, int flags)
status = 0;
while ((n = parsecmd(0)) != NEOF) {
- evaltree(n, flags);
+ evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
status = exitstatus;
popstackmark(&smark);
if (evalskip)
diff --git a/usr/dash/eval.h b/usr/dash/eval.h
index 5ccfa9f17d11f..dc8acd2a5c4a7 100644
--- a/usr/dash/eval.h
+++ b/usr/dash/eval.h
@@ -46,6 +46,10 @@ struct backcmd { /* result of evalbackcmd */
struct job *jp; /* job structure for command */
};
+/* flags in argument to evaltree */
+#define EV_EXIT 01 /* exit after evaluating tree */
+#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
+
int evalstring(char *, int);
union node; /* BLETCH for ansi C */
void evaltree(union node *, int);
diff --git a/usr/dash/main.c b/usr/dash/main.c
index 7df3c44177b3a..f79ad7ddac111 100644
--- a/usr/dash/main.c
+++ b/usr/dash/main.c
@@ -171,7 +171,7 @@ state2:
state3:
state = 4;
if (minusc)
- evalstring(minusc, 0);
+ evalstring(minusc, sflag ? 0 : EV_EXIT);
if (sflag || minusc == NULL) {
state4: /* XXX ??? - why isn't this before the "if" statement */
diff --git a/usr/dash/mktokens b/usr/dash/mktokens
index 43d76ce13dc9d..fa6ccf7839771 100644
--- a/usr/dash/mktokens
+++ b/usr/dash/mktokens
@@ -71,13 +71,16 @@ TEND 1 "}"
nl=`wc -l /tmp/ka$$`
exec > token.h
awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
+
+exec > token_vars.h
+
echo '
/* Array indicating which tokens mark the end of a list */
-const char tokendlist[] = {'
+static const char tokendlist[] = {'
awk '{print "\t" $2 ","}' /tmp/ka$$
echo '};
-const char *const tokname[] = {'
+static const char *const tokname[] = {'
sed -e 's/"/\\"/g' \
-e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
/tmp/ka$$
@@ -85,7 +88,7 @@ echo '};
'
sed 's/"//g' /tmp/ka$$ | awk '
/TNOT/{print "#define KWDOFFSET " NR-1; print "";
- print "STATIC const char *const parsekwd[] = {"}
+ print "static const char *const parsekwd[] = {"}
/TNOT/,/neverfound/{if (last) print " \"" last "\","; last = $3}
END{print " \"" last "\"\n};"}'
diff --git a/usr/dash/parser.c b/usr/dash/parser.c
index 6e076a597d388..572cbcd5986c6 100644
--- a/usr/dash/parser.c
+++ b/usr/dash/parser.c
@@ -64,7 +64,7 @@
*/
/* values returned by readtoken */
-#include "token.h"
+#include "token_vars.h"
@@ -86,7 +86,7 @@ struct heredoc *heredoclist; /* list of here documents to read */
int doprompt; /* if set, prompt the user */
int needprompt; /* true if interactive and at start of line */
int lasttoken; /* last token read */
-MKINIT int tokpushback; /* last token pushed back */
+int tokpushback; /* last token pushed back */
char *wordtext; /* text of last word returned by readtoken */
int checkkwd;
struct nodelist *backquotelist;
@@ -210,6 +210,7 @@ list(int nlflag)
parseheredoc();
else
pungetc(); /* push back EOF on input */
+ tokpushback++;
return n1;
default:
if (nlflag == 1)
diff --git a/usr/dash/parser.h b/usr/dash/parser.h
index e6caed632fd85..2875cce6d4241 100644
--- a/usr/dash/parser.h
+++ b/usr/dash/parser.h
@@ -34,6 +34,8 @@
* @(#)parser.h 8.3 (Berkeley) 5/4/95
*/
+#include "token.h"
+
/* control characters in argument strings */
#define CTL_FIRST -127 /* first 'special' character */
#define CTLESC -127 /* escape next character */
@@ -73,6 +75,7 @@
* must be distinct from NULL, so we use the address of a variable that
* happens to be handy.
*/
+extern int lasttoken;
extern int tokpushback;
#define NEOF ((union node *)&tokpushback)
extern int whichprompt; /* 1 == PS1, 2 == PS2 */
@@ -91,3 +94,8 @@ goodname(const char *p)
{
return !*endofname(p);
}
+
+static inline int parser_eof(void)
+{
+ return tokpushback && lasttoken == TEOF;
+}