From 47e3d475df6244a48b73421cd4210b64c392df8d Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 19 Oct 2021 09:35:59 -0700 Subject: feat(rc): cleaner process watching for each job --- sys/cmd/rc/code.c | 4 +- sys/cmd/rc/exec.c | 188 ++++++++++--------- sys/cmd/rc/input.c | 10 +- sys/cmd/rc/job.c | 82 ++++++++ sys/cmd/rc/lex.c | 17 +- sys/cmd/rc/main.c | 7 +- sys/cmd/rc/parse.c | 529 +++++++++++++++++++++++++++++++++++++++++----------- sys/cmd/rc/parse.h | 2 +- sys/cmd/rc/prompt.c | 4 +- sys/cmd/rc/rc.h | 36 ++-- sys/cmd/rc/syntax.y | 5 +- sys/cmd/rc/var.c | 12 +- sys/cmd/rc/wait.c | 94 +++++++--- 13 files changed, 725 insertions(+), 265 deletions(-) create mode 100644 sys/cmd/rc/job.c (limited to 'sys/cmd') diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c index 8dec021..d4dd6e1 100644 --- a/sys/cmd/rc/code.c +++ b/sys/cmd/rc/code.c @@ -50,7 +50,7 @@ walk(Tree *node) switch(node->type){ default: - print(errio, "bad type %d in interpreter walk\n", node->type); + print(shell.err, "bad type %d in interpreter walk\n", node->type); break; case '$': @@ -152,7 +152,7 @@ copycode(Code *c) int compile(Tree *node) { - flush(errio); + flush(shell.err); //print(errio, "%t\n", node); interpreter.i = 0; diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c index 80cd645..d78cb5d 100644 --- a/sys/cmd/rc/exec.c +++ b/sys/cmd/rc/exec.c @@ -31,10 +31,10 @@ static void pushword(char *str) { - if(!proc->args) + if(!runner->args) fatal("attempt to push on empty argument stack\n"); - proc->args->word = makeword(str, proc->args->word); + runner->args->word = makeword(str, runner->args->word); } static @@ -42,14 +42,14 @@ void popword(void) { Word *w; - if(!proc->args) + if(!runner->args) fatal("tried to pop word on empty argument stack\n"); - w = proc->args->word; + w = runner->args->word; if(!w) fatal("tried to pop word but nothing there\n"); - proc->args->word = w->link; + runner->args->word = w->link; efree(w->str); efree(w); } @@ -101,21 +101,21 @@ pushlist(void) List *stack = emalloc(sizeof(*stack)); stack->word = nil; - stack->link = proc->args; + stack->link = runner->args; - proc->args = stack; + runner->args = stack; } static void poplist(void) { - List *stack = proc->args; + List *stack = runner->args; if(!stack) fatal("attempted to pop an empty argument stack\n"); freelist(stack->word); - proc->args = stack->link; + runner->args = stack->link; efree(stack); } @@ -140,12 +140,12 @@ void xx(void) { popword(); // "exec" - if(!proc->args->word){ + if(!runner->args->word){ Xerror("empty argument list"); return; } - execute(proc->args->word, path(proc->args->word->str)); + execute(runner->args->word, path(runner->args->word->str)); poplist(); } @@ -160,15 +160,15 @@ xforkx(void) case -1: return -1; case 0: // child - clearwait(proc); + clearwait(runner); if(shell.interactive){ - proc->pid = getpid(); - if(proc->pgid <= 0) - proc->pgid = proc->pid; + runner->pid = getpid(); + if(runner->pgid <= 0) + runner->pgid = runner->pid; - setpgid(pid, proc->pgid); - tcsetpgrp(0, proc->pgid); + setpgid(pid, runner->pgid); + tcsetpgrp(0, runner->pgid); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); @@ -181,16 +181,16 @@ xforkx(void) pushword("exec"); xx(); - exit(1); // NOTE: xx does not return! + exit(2); // NOTE: xx does not return! /*unreachable*/ default: // parent - addwait(proc, pid); + addwait(runner, pid); /* ensure the state matches for parent and child */ - proc->pid = pid; - if(proc->pgid <= 0) - proc->pgid = pid; - setpgid(pid, proc->pgid); + runner->pid = pid; + if(runner->pgid <= 0) + runner->pgid = pid; + setpgid(pid, runner->pgid); return pid; } @@ -205,9 +205,9 @@ pushredir(int type, int from, int to) r->type = type; r->from = from; r->to = to; - r->link = proc->redir; + r->link = runner->redir; - proc->redir = r; + runner->redir = r; } /* byte code */ @@ -219,17 +219,30 @@ run(Code *c, int pc, Var *local) new->code.i = pc; new->code.exe = copycode(c); - new->args = nil; - new->local = local; + new->cmd.path = nil; new->cmd.io = nil; + + new->args = nil; + new->local = local; + new->redir = nil; + + new->flag.i = 0; new->flag.eof = 0; - new->line = 1; - new->link = proc; + new->wait.status = 0; + new->wait.len = 0; + new->wait.cap = 0; + new->wait.on = nil; + + new->status = 0; new->pgid = new->pid = -1; - proc = new; + new->line = 0; + new->link = runner; + new->next = nil; + + runner = new; } // ----------------------------------------------------------------------- @@ -307,12 +320,12 @@ xdot(void) } #endif /* get input file */ - if(!proc->args->word){ + if(!runner->args->word){ Xerror("usage: . [-i] file [arg ...]\n"); return; } - base = strdup(proc->args->word->str); + base = strdup(runner->args->word->str); popword(); for(fd=-1, p=path(base); p; p = p->link){ strcpy(file, p->str); @@ -326,23 +339,23 @@ xdot(void) } if(fd<0){ - print(errio, "%s: ", base); + print(shell.err, "%s: ", base); //setstatus("can't open"); Xerror(".: can't open\n"); return; } /* set up for a new command loop */ - old = proc; // store pointer to old code + old = runner; // store pointer to old code run(dotcmd, 1, nil); /* operations on new command stack */ pushredir(Rclose, fd, 0); - proc->cmd.path = base; - proc->cmd.io = openfd(fd); + runner->cmd.path = base; + runner->cmd.io = openfd(fd); /* push $* value */ pushlist(); - proc->args->word = old->args->word; + runner->args->word = old->args->word; /* free caller's copy of $* */ argv = old->args; @@ -361,7 +374,7 @@ xjob(void) int i; Thread *job; - for(i = 0, job = shell.jobs; job; job = job->next) + for(i=0, job = shell.jobs; job; job = job->next, i++) report(job,i); poplist(); @@ -376,27 +389,23 @@ xfg(void) popword(); // fg /* get input job id */ - if(!proc->args->word){ - print(errio, "usage: fg [pid|\%num]\n"); + if(!runner->args->word){ + print(shell.err, "usage: fg [pid|\%num]\n"); poplist(); return; } - i = atoi(proc->args->word->str); + i = atoi(runner->args->word->str); popword(); // [jobid] for(job=shell.jobs; i > 0; job=job->next, --i) ; - assert(!job->flag.done); - - addwait(job, job->pid); - job->flag.stop = 0; poplist(); // this goes here? - job->link = proc, proc = job; // XXX: can this leave orphans? + wakeup(job); + job->link = runner, runner = job; // XXX: can this leave zombies? foreground(job, 1); - printf("hi\n"); } void @@ -434,8 +443,8 @@ xboot(int argc, char *argv[]) /* main interpreter loop */ for(;;){ - proc->code.i++; - (*proc->code.exe[proc->code.i-1].f)(); + runner->code.i++; + (*runner->code.exe[runner->code.i-1].f)(); } } @@ -451,52 +460,55 @@ Xmark(void) void Xerror(char *msg) { - print(errio, "rc: %s", msg); - flush(errio); - while(!proc->flag.i) + print(shell.err, "rc: %s", msg); + flush(shell.err); + while(!runner->flag.i) Xreturn(); } void Xreturn(void) { - Thread *run = proc; + Thread *run = runner; + switch(run->wait.status){ /* * If our job is still running we must: * 1. move program one step back to rerun Xreturn upon recall * 2. return to our calling thread * 3. don't free! */ - if(run->flag.stop){ + case PStop: run->code.i--; - proc = run->link; + runner = run->link; return; - } - /* * If our job has finished: * 1. remove from our list - * 2. clean up its memory! + * 2. continue to clean up its memory */ - if(run->flag.done) + case PDone: deljob(run); + /* fallthrough */ + default: + ; + } while(run->args) poplist(); freecode(run->code.exe); - efree(run->wait.pid); + efree(run->wait.on); - proc = run->link; + runner = run->link; efree(run); - if(!proc) + if(!runner) exit(0); } void Xword(void) { - pushword(proc->code.exe[proc->code.i++].s); + pushword(runner->code.exe[runner->code.i++].s); } void @@ -506,18 +518,18 @@ Xdollar(void) char *s, *t; Word *a, *star; - if(count(proc->args->word)!=1){ + if(count(runner->args->word)!=1){ Xerror("variable name not singleton!\n"); return; } - s = proc->args->word->str; + s = runner->args->word->str; // deglob(s); n = 0; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; - a = proc->args->link->word; + a = runner->args->link->word; if(n==0 || *t) a = copywords(var(s)->val, a); @@ -532,7 +544,7 @@ Xdollar(void) } poplist(); - proc->args->word = a; + runner->args->word = a; } void @@ -540,22 +552,22 @@ Xassign(void) { Var *v; - if(count(proc->args->word)!=1){ + if(count(runner->args->word)!=1){ Xerror("variable name not singleton!\n"); return; } //deglob(runq->argv->words->word); - v = var(proc->args->word->str); + v = var(runner->args->word->str); poplist(); //globlist(); freewords(v->val); - v->val = proc->args->word; + v->val = runner->args->word; v->new = 1; if(v->update) v->update(v); - proc->args->word = nil; + runner->args->word = nil; poplist(); } @@ -566,8 +578,8 @@ Xreadcmd(void) Thread *root; Word *prompt; - flush(errio); - root = proc; + flush(shell.err); + root = runner; if(yyparse()){ exit(1); @@ -576,22 +588,22 @@ Xreadcmd(void) run(compiled, 1, root->local); } - // killzombies(); + killzombies(); freeparsetree(); } void Xlocal(void) { - if(count(proc->args->word)!=1){ + if(count(runner->args->word)!=1){ Xerror("variable name must be singleton\n"); return; } //deglob(shell->args->word->str); - proc->local = makevar(strdup(proc->args->word->str), proc->local); - proc->local->val = copywords(proc->args->link->word, nil); - proc->local->new = 1; + runner->local = makevar(strdup(runner->args->word->str), runner->local); + runner->local->val = copywords(runner->args->link->word, nil); + runner->local->new = 1; poplist(); poplist(); @@ -600,13 +612,11 @@ Xlocal(void) void Xunlocal(void) { - Var *v = proc->local, *hide; + Var *v = runner->local, *hide; if(!v) fatal("Xunlocal: no locals!\n", 0); - printf("unlocal\n"); - - proc->local = v->link; + runner->local = v->link; hide = var(v->name); hide->new = 1; @@ -623,19 +633,18 @@ Xbasic(void) int pid, status; struct Builtin *b; - arg = proc->args->word; + arg = runner->args->word; if(!arg){ Xerror("empty argument list\n"); return; } - /* print(errio, "recieved arg: %v\n", arg); // for debugging */ - flush(errio); + flush(shell.err); v = var(arg->str); if(v->func){ - // xfunc(v); return; } + // see if it matches a builtin for(b = builtin; b->name; b++){ if(strcmp(b->name, arg->str)==0){ @@ -645,8 +654,7 @@ Xbasic(void) } /* if we are here then it's an external command */ - killzombies(); - addjob(proc); + addjob(runner); // run the external command if((pid = xforkx()) < 0) { @@ -657,9 +665,9 @@ Xbasic(void) poplist(); if(!shell.interactive) - waitall(proc); + waitall(runner); - foreground(proc, 0); // waits for child + foreground(runner, 0); // waits for child } void diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c index 4c6b37f..228b2d8 100644 --- a/sys/cmd/rc/input.c +++ b/sys/cmd/rc/input.c @@ -995,7 +995,7 @@ notty(void) for(;;){ c = fgetc(stdin); - put(&proc->cmd.io, c); + put(&runner->cmd.io, c); } } @@ -1019,17 +1019,17 @@ readline(char *prompt) int n; // reset the command buffer - proc->cmd.io->e = proc->cmd.io->b = proc->cmd.io->buf; + runner->cmd.io->e = runner->cmd.io->b = runner->cmd.io->buf; if(!shell.interactive) return notty(); - if((n = raw(proc->cmd.io->e, proc->cmd.io->cap-1, prompt)) == -1) + if((n = raw(runner->cmd.io->e, runner->cmd.io->cap-1, prompt)) == -1) return 0; - proc->cmd.io->e += n; + runner->cmd.io->e += n; /* insert a newline character at the end */ - put(&proc->cmd.io, '\n'); + put(&runner->cmd.io, '\n'); printf("\n"); return 1; diff --git a/sys/cmd/rc/job.c b/sys/cmd/rc/job.c new file mode 100644 index 0000000..779ce6c --- /dev/null +++ b/sys/cmd/rc/job.c @@ -0,0 +1,82 @@ +#include "rc.h" + +#include +#include + +// ----------------------------------------------------------------------- +// exports + +Thread * +getjob(int pid, int *index) +{ + int i; + Thread *job; + for(i=0,job=shell.jobs; job && job->pid != pid; i++, job=job->next) + ; + + return job; +} + +void +report(Thread *job, int index) +{ + switch(job->wait.status){ + case PDone: + print(shell.err, "job %d [%d]: done\n", index, job->pid); + break; + case PStop: + print(shell.err, "job %d [%d]: suspended\n", index, job->pid); + break; + case PAgain: + print(shell.err, "job %d [%d]: continued\n", index, job->pid); + break; + case PRun: + print(shell.err, "job %d [%d]: running\n", index, job->pid); + break; + default: + fatal("bad wait status: %d\n", job->wait.status); + } +} + +void +wakeup(Thread *t) +{ + int i; + t->wait.status = PRun; + for(i=0; i < t->wait.len; i++){ + if(t->wait.on[i].status == PStop) + t->wait.on[i].status = PRun; + } +} + +void +foreground(Thread *job, int signal) +{ + tcsetpgrp(0, job->pgid); + if(signal){ + if(kill(-job->pgid, SIGCONT) < 0) + perror("kill[SIGCONT]"); + } + + waitall(job); + + tcsetpgrp(0, shell.pid); +} + +void +addjob(Thread *job) +{ + job->next = shell.jobs; + shell.jobs = job; +} + +void +deljob(Thread *job) +{ + Thread **jp; + + for(jp = &shell.jobs; *jp && *jp != job; jp = &(*jp)->next) + ; + + *jp = job->next; +} diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c index e7c7d7d..b4a2e8c 100644 --- a/sys/cmd/rc/lex.c +++ b/sys/cmd/rc/lex.c @@ -15,16 +15,17 @@ struct Lexer static struct Lexer lexer = { .c={0, EOF}, .doprompt=1 }; void -yyerror(char *msg) +yyerror(const char *msg) { - print(errio, "\nrc: "); + print(shell.err, "\nrc:%d: ", runner->line); if(lexer.buf[0] && lexer.buf[0]!='\n') - print(errio, "@ %q: ", lexer.buf); + print(shell.err, "%q: ", lexer.buf); - print(errio, "%s\n", msg); - flush(errio); + print(shell.err, "%s\n", msg); + flush(shell.err); + /* consume remaining tokens */ while(lexer.c[0] !='\n' && lexer.c[0] != EOF) advance(); } @@ -40,18 +41,18 @@ readc(void) peek = EOF; return c; } - if(proc->flag.eof) + if(runner->flag.eof) return EOF; if(!prompt(&lexer.doprompt)) exit(1); // XXX: hack for signal handling right now... - c = get(proc->cmd.io); + c = get(runner->cmd.io); lexer.doprompt = lexer.doprompt || c=='\n' || c==EOF; if(c==EOF) - proc->flag.eof = 1; + runner->flag.eof = 1; return c; } diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c index d1bbd06..557030a 100644 --- a/sys/cmd/rc/main.c +++ b/sys/cmd/rc/main.c @@ -8,9 +8,8 @@ // ----------------------------------------------------------------------- // globals -Io *errio = nil; -Thread *proc = nil; -Shell shell = { 0 }; +Thread *runner = nil; +Shell shell = { 0 }; // ----------------------------------------------------------------------- // functions @@ -57,7 +56,7 @@ main(int argc, char *argv[]) Code bootstrap[32]; char num[12]; - errio = openfd(2); + shell.err = openfd(2); initenv(); initpath(); diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c index e2e4afa..42834ed 100644 --- a/sys/cmd/rc/parse.c +++ b/sys/cmd/rc/parse.c @@ -67,12 +67,12 @@ /* First part of user prologue. */ -#line 5 "sys/cmd/rc/syntax.y" +#line 7 "sys/cmd/rc/syntax.y" #include "rc.h" int yylex(void); - void yyerror(char *); + void yyerror(const char *); #line 78 "sys/cmd/rc/parse.c" @@ -133,14 +133,15 @@ enum yysymbol_kind_t YYSYMBOL_cmds = 28, /* cmds */ YYSYMBOL_cmdsln = 29, /* cmdsln */ YYSYMBOL_ifbody = 30, /* ifbody */ - YYSYMBOL_cmd = 31, /* cmd */ - YYSYMBOL_basic = 32, /* basic */ - YYSYMBOL_atom = 33, /* atom */ - YYSYMBOL_word = 34, /* word */ - YYSYMBOL_executable = 35, /* executable */ - YYSYMBOL_nonkeyword = 36, /* nonkeyword */ - YYSYMBOL_keyword = 37, /* keyword */ - YYSYMBOL_nl = 38 /* nl */ + YYSYMBOL_assign = 31, /* assign */ + YYSYMBOL_cmd = 32, /* cmd */ + YYSYMBOL_basic = 33, /* basic */ + YYSYMBOL_atom = 34, /* atom */ + YYSYMBOL_word = 35, /* word */ + YYSYMBOL_executable = 36, /* executable */ + YYSYMBOL_nonkeyword = 37, /* nonkeyword */ + YYSYMBOL_keyword = 38, /* keyword */ + YYSYMBOL_nl = 39 /* nl */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; @@ -338,7 +339,7 @@ typedef int yy_state_fast_t; #define YY_ASSERT(E) ((void) (0 && (E))) -#if !defined yyoverflow +#if 1 /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -403,7 +404,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif -#endif /* !defined yyoverflow */ +#endif /* 1 */ #if (! defined yyoverflow \ && (! defined __cplusplus \ @@ -466,18 +467,18 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 24 +#define YYFINAL 25 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 49 +#define YYLAST 53 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 22 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 17 +#define YYNNTS 18 /* YYNRULES -- Number of rules. */ -#define YYNRULES 33 +#define YYNRULES 35 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 48 +#define YYNSTATES 52 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 266 @@ -527,17 +528,17 @@ static const yytype_int8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int8 yyrline[] = { - 0, 34, 34, 35, 38, 39, 42, 43, 46, 49, - 52, 53, 56, 57, 60, 61, 67, 68, 69, 70, - 73, 74, 83, 84, 87, 88, 91, 92, 95, 96, - 99, 99, 101, 103 + 0, 36, 36, 37, 40, 41, 44, 45, 48, 51, + 54, 55, 58, 59, 62, 63, 66, 69, 70, 71, + 72, 73, 76, 77, 86, 87, 90, 91, 94, 95, + 98, 99, 102, 102, 104, 106 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) -#if YYDEBUG || 0 +#if 1 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; @@ -550,8 +551,8 @@ static const char *const yytname[] = "Telse", "Tbang", "Targs", "Tbasic", "Tparen", "Tblock", "Twhile", "'\\n'", "'$'", "'('", "')'", "'{'", "'}'", "';'", "'&'", "'='", "'^'", "$accept", "rc", "line", "body", "paren", "block", "cmds", "cmdsln", - "ifbody", "cmd", "basic", "atom", "word", "executable", "nonkeyword", - "keyword", "nl", YY_NULLPTR + "ifbody", "assign", "cmd", "basic", "atom", "word", "executable", + "nonkeyword", "keyword", "nl", YY_NULLPTR }; static const char * @@ -561,7 +562,7 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #endif -#define YYPACT_NINF (-10) +#define YYPACT_NINF (-14) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) @@ -575,11 +576,12 @@ yysymbol_name (yysymbol_kind_t yysymbol) STATE-NUM. */ static const yytype_int8 yypact[] = { - 3, -10, -2, 21, 7, 15, 9, -10, 7, 22, - 21, 10, -10, 7, -10, -10, -10, -10, -10, -10, - 18, -10, 7, 20, -10, -10, -10, -10, -10, -10, - 23, 21, 27, 1, -10, -10, -10, 21, -10, -10, - -10, 38, -10, -10, -10, -10, 1, -10 + 3, -14, -13, 24, 10, 5, 19, -14, 10, 10, + 28, 24, -3, -14, 10, -14, -14, -14, -14, -14, + -14, -2, -14, 10, 26, -14, -14, -14, -14, -14, + -14, -14, 21, 24, 24, 25, 8, -14, -14, -14, + 24, 21, -14, -14, -14, 38, -14, -14, -14, -14, + 8, -14 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -587,25 +589,26 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_int8 yydefact[] = { - 16, 28, 0, 0, 16, 0, 0, 18, 16, 4, - 17, 20, 26, 16, 32, 30, 31, 29, 22, 23, - 0, 12, 16, 6, 1, 3, 5, 10, 11, 24, - 21, 0, 0, 16, 9, 7, 13, 0, 27, 8, - 33, 18, 19, 14, 25, 32, 16, 15 + 17, 30, 0, 0, 17, 0, 0, 19, 17, 17, + 4, 18, 22, 28, 17, 34, 32, 33, 31, 24, + 25, 0, 12, 17, 6, 1, 3, 5, 20, 10, + 11, 26, 23, 0, 0, 0, 17, 9, 7, 13, + 0, 16, 29, 8, 35, 19, 21, 14, 27, 34, + 17, 15 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -10, -10, 37, 5, -10, 14, 29, -10, -10, 0, - -10, -9, -10, -10, -1, -10, 4 + -14, -14, 40, 11, -14, 13, 22, -14, -14, -14, + 0, -14, 1, 18, -14, -1, -14, 4 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - 0, 5, 6, 20, 14, 7, 21, 22, 42, 23, - 10, 17, 30, 11, 12, 19, 33 + 0, 5, 6, 21, 15, 7, 22, 23, 46, 9, + 24, 11, 31, 32, 12, 13, 20, 36 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -613,20 +616,22 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { - 9, 29, 18, -2, 1, 2, 1, 2, 9, 18, - 1, 2, 13, 40, 3, 24, 3, 4, 32, 4, - 3, 25, 38, 4, 1, 15, 16, 35, 44, 8, - 18, 31, 36, 43, 3, 34, 18, 8, 27, 28, - 27, 28, 39, 45, 37, 26, 47, 41, 0, 46 + 10, 14, 19, -2, 18, 25, 1, 2, 10, 28, + 19, 1, 2, 1, 2, 37, 3, 33, 34, 4, + 44, 3, 8, 3, 4, 35, 4, 1, 16, 17, + 8, 26, 19, 19, 38, 42, 47, 3, 39, 19, + 43, 48, 40, 49, 29, 30, 29, 30, 27, 45, + 51, 41, 0, 50 }; static const yytype_int8 yycheck[] = { - 0, 10, 3, 0, 3, 4, 3, 4, 8, 10, - 3, 4, 14, 12, 13, 0, 13, 16, 13, 16, - 13, 12, 31, 16, 3, 4, 5, 22, 37, 0, - 31, 21, 12, 33, 13, 17, 37, 8, 18, 19, - 18, 19, 15, 5, 21, 8, 46, 33, -1, 45 + 0, 14, 3, 0, 3, 0, 3, 4, 8, 9, + 11, 3, 4, 3, 4, 17, 13, 20, 21, 16, + 12, 13, 0, 13, 16, 14, 16, 3, 4, 5, + 8, 12, 33, 34, 23, 34, 36, 13, 12, 40, + 15, 40, 21, 5, 18, 19, 18, 19, 8, 36, + 50, 33, -1, 49 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of @@ -634,28 +639,29 @@ static const yytype_int8 yycheck[] = static const yytype_int8 yystos[] = { 0, 3, 4, 13, 16, 23, 24, 27, 28, 31, - 32, 35, 36, 14, 26, 4, 5, 33, 36, 37, - 25, 28, 29, 31, 0, 12, 24, 18, 19, 33, - 34, 21, 25, 38, 17, 25, 12, 21, 33, 15, - 12, 27, 30, 31, 33, 5, 38, 31 + 32, 33, 36, 37, 14, 26, 4, 5, 34, 37, + 38, 25, 28, 29, 32, 0, 12, 24, 32, 18, + 19, 34, 35, 20, 21, 25, 39, 17, 25, 12, + 21, 35, 34, 15, 12, 27, 30, 32, 34, 5, + 39, 32 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 22, 23, 23, 24, 24, 25, 25, 26, 27, - 28, 28, 29, 29, 30, 30, 31, 31, 31, 31, + 28, 28, 29, 29, 30, 30, 31, 32, 32, 32, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, - 37, 37, 38, 38 + 37, 37, 38, 38, 39, 39 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 1, 2, 1, 2, 3, 3, - 2, 2, 1, 2, 1, 4, 0, 1, 1, 4, - 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, - 1, 1, 0, 2 + 2, 2, 1, 2, 1, 4, 3, 0, 1, 1, + 2, 4, 1, 2, 1, 1, 1, 3, 1, 3, + 1, 2, 1, 1, 0, 2 }; @@ -838,8 +844,275 @@ int yydebug; #endif +/* Context of a parse error. */ +typedef struct +{ + yy_state_t *yyssp; + yysymbol_kind_t yytoken; +} yypcontext_t; + +/* Put in YYARG at most YYARGN of the expected tokens given the + current YYCTX, and return the number of tokens stored in YYARG. If + YYARG is null, return the number of expected tokens (guaranteed to + be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. + Return 0 if there are more than YYARGN expected tokens, yet fill + YYARG up to YYARGN. */ +static int +yypcontext_expected_tokens (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + int yyn = yypact[+*yyctx->yyssp]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = YYSYMBOL_YYEMPTY; + return yycount; +} + + + + +#ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) +# else +/* Return the length of YYSTR. */ +static YYPTRDIFF_T +yystrlen (const char *yystr) +{ + YYPTRDIFF_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +#endif + +#ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + while ((*yyd++ = *yys++) != '\0') + continue; + return yyd - 1; +} +# endif +#endif + +#ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYPTRDIFF_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYPTRDIFF_T yyn = 0; + char const *yyp = yystr; + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else + return yystrlen (yystr); +} +#endif + + +static int +yy_syntax_error_arguments (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yyctx->yytoken != YYSYMBOL_YYEMPTY) + { + int yyn; + if (yyarg) + yyarg[yycount] = yyctx->yytoken; + ++yycount; + yyn = yypcontext_expected_tokens (yyctx, + yyarg ? yyarg + 1 : yyarg, yyargn - 1); + if (yyn == YYENOMEM) + return YYENOMEM; + else + yycount += yyn; + } + return yycount; +} + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + const yypcontext_t *yyctx) +{ + enum { YYARGS_MAX = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + yysymbol_kind_t yyarg[YYARGS_MAX]; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; + + /* Actual size of YYARG. */ + int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); + if (yycount == YYENOMEM) + return YYENOMEM; + + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + /* Compute error message size. Don't count the "%s"s, but reserve + room for the terminator. */ + yysize = yystrlen (yyformat) - 2 * yycount + 1; + { + int yyi; + for (yyi = 0; yyi < yycount; ++yyi) + { + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return YYENOMEM; + } + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return -1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); + yyformat += 2; + } + else + { + ++yyp; + ++yyformat; + } + } + return 0; +} /*-----------------------------------------------. @@ -908,7 +1181,10 @@ yyparse (void) action routines. */ YYSTYPE yyval; - + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) @@ -1119,109 +1395,121 @@ yyreduce: switch (yyn) { case 2: /* rc: %empty */ -#line 34 "sys/cmd/rc/syntax.y" +#line 36 "sys/cmd/rc/syntax.y" { return 0; } -#line 1125 "sys/cmd/rc/parse.c" +#line 1401 "sys/cmd/rc/parse.c" break; case 3: /* rc: line '\n' */ -#line 35 "sys/cmd/rc/syntax.y" +#line 37 "sys/cmd/rc/syntax.y" { return compile((yyvsp[-1].tree)); } -#line 1131 "sys/cmd/rc/parse.c" +#line 1407 "sys/cmd/rc/parse.c" break; case 5: /* line: cmds line */ -#line 39 "sys/cmd/rc/syntax.y" +#line 41 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); } -#line 1137 "sys/cmd/rc/parse.c" +#line 1413 "sys/cmd/rc/parse.c" break; case 7: /* body: cmdsln body */ -#line 43 "sys/cmd/rc/syntax.y" +#line 45 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(';', (yyvsp[-1].tree), (yyvsp[0].tree)); } -#line 1143 "sys/cmd/rc/parse.c" +#line 1419 "sys/cmd/rc/parse.c" break; case 8: /* paren: '(' body ')' */ -#line 46 "sys/cmd/rc/syntax.y" +#line 48 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tparen, (yyvsp[-1].tree)); } -#line 1149 "sys/cmd/rc/parse.c" +#line 1425 "sys/cmd/rc/parse.c" break; case 9: /* block: '{' body '}' */ -#line 49 "sys/cmd/rc/syntax.y" +#line 51 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tblock, (yyvsp[-1].tree)); } -#line 1155 "sys/cmd/rc/parse.c" +#line 1431 "sys/cmd/rc/parse.c" break; case 11: /* cmds: cmd '&' */ -#line 53 "sys/cmd/rc/syntax.y" +#line 55 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1('&', (yyvsp[-1].tree)); } -#line 1161 "sys/cmd/rc/parse.c" +#line 1437 "sys/cmd/rc/parse.c" break; case 14: /* ifbody: cmd */ -#line 60 "sys/cmd/rc/syntax.y" +#line 62 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(Tif, nil, (yyvsp[0].tree)); } -#line 1167 "sys/cmd/rc/parse.c" +#line 1443 "sys/cmd/rc/parse.c" break; case 15: /* ifbody: block Telse nl cmd */ -#line 61 "sys/cmd/rc/syntax.y" +#line 63 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree3(Tif, nil, (yyvsp[-3].tree), (yyvsp[-2].tree)); } -#line 1173 "sys/cmd/rc/parse.c" +#line 1449 "sys/cmd/rc/parse.c" + break; + + case 16: /* assign: executable '=' word */ +#line 66 "sys/cmd/rc/syntax.y" + { (yyval.tree) = maketree2('=', (yyvsp[-2].tree), (yyvsp[0].tree)); } +#line 1455 "sys/cmd/rc/parse.c" break; - case 16: /* cmd: %empty */ -#line 67 "sys/cmd/rc/syntax.y" + case 17: /* cmd: %empty */ +#line 69 "sys/cmd/rc/syntax.y" { (yyval.tree) = nil; } -#line 1179 "sys/cmd/rc/parse.c" +#line 1461 "sys/cmd/rc/parse.c" break; - case 17: /* cmd: basic */ -#line 68 "sys/cmd/rc/syntax.y" + case 18: /* cmd: basic */ +#line 70 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tbasic, (yyvsp[0].tree)); } -#line 1185 "sys/cmd/rc/parse.c" +#line 1467 "sys/cmd/rc/parse.c" break; - case 19: /* cmd: Tif paren nl ifbody */ -#line 70 "sys/cmd/rc/syntax.y" + case 20: /* cmd: assign cmd */ +#line 72 "sys/cmd/rc/syntax.y" + { (yyval.tree) = hangchild1((yyvsp[-1].tree), (yyvsp[0].tree), 2); } +#line 1473 "sys/cmd/rc/parse.c" + break; + + case 21: /* cmd: Tif paren nl ifbody */ +#line 73 "sys/cmd/rc/syntax.y" { (yyval.tree) = hangchild1((yyvsp[-2].tree), (yyvsp[-3].tree), 0); } -#line 1191 "sys/cmd/rc/parse.c" +#line 1479 "sys/cmd/rc/parse.c" break; - case 21: /* basic: basic word */ -#line 74 "sys/cmd/rc/syntax.y" + case 23: /* basic: basic word */ +#line 77 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2(Targs, (yyvsp[-1].tree), (yyvsp[0].tree)); } -#line 1197 "sys/cmd/rc/parse.c" +#line 1485 "sys/cmd/rc/parse.c" break; - case 23: /* atom: keyword */ -#line 84 "sys/cmd/rc/syntax.y" + case 25: /* atom: keyword */ +#line 87 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1(Tword, (yyvsp[0].tree)); } -#line 1203 "sys/cmd/rc/parse.c" +#line 1491 "sys/cmd/rc/parse.c" break; - case 25: /* word: word '^' atom */ -#line 88 "sys/cmd/rc/syntax.y" + case 27: /* word: word '^' atom */ +#line 91 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); } -#line 1209 "sys/cmd/rc/parse.c" +#line 1497 "sys/cmd/rc/parse.c" break; - case 27: /* executable: executable '^' atom */ -#line 92 "sys/cmd/rc/syntax.y" + case 29: /* executable: executable '^' atom */ +#line 95 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree2('^', (yyvsp[-2].tree), (yyvsp[0].tree)); } -#line 1215 "sys/cmd/rc/parse.c" +#line 1503 "sys/cmd/rc/parse.c" break; - case 29: /* nonkeyword: '$' atom */ -#line 96 "sys/cmd/rc/syntax.y" + case 31: /* nonkeyword: '$' atom */ +#line 99 "sys/cmd/rc/syntax.y" { (yyval.tree) = maketree1('$', (yyvsp[0].tree)); } -#line 1221 "sys/cmd/rc/parse.c" +#line 1509 "sys/cmd/rc/parse.c" break; -#line 1225 "sys/cmd/rc/parse.c" +#line 1513 "sys/cmd/rc/parse.c" default: break; } @@ -1268,7 +1556,37 @@ yyerrlab: if (!yyerrstatus) { ++yynerrs; - yyerror (YY_("syntax error")); + { + yypcontext_t yyctx + = {yyssp, yytoken}; + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == -1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = YY_CAST (char *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); + if (yymsg) + { + yysyntax_error_status + = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + yymsgp = yymsg; + } + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = YYENOMEM; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == YYENOMEM) + YYNOMEM; + } } if (yyerrstatus == 3) @@ -1410,9 +1728,10 @@ yyreturnlab: if (yyss != yyssa) YYSTACK_FREE (yyss); #endif - + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); return yyresult; } -#line 104 "sys/cmd/rc/syntax.y" +#line 107 "sys/cmd/rc/syntax.y" diff --git a/sys/cmd/rc/parse.h b/sys/cmd/rc/parse.h index 5328340..8fc661f 100644 --- a/sys/cmd/rc/parse.h +++ b/sys/cmd/rc/parse.h @@ -85,7 +85,7 @@ extern int yydebug; #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { -#line 20 "sys/cmd/rc/syntax.y" +#line 22 "sys/cmd/rc/syntax.y" struct Tree *tree; diff --git a/sys/cmd/rc/prompt.c b/sys/cmd/rc/prompt.c index 21078e8..94022ca 100644 --- a/sys/cmd/rc/prompt.c +++ b/sys/cmd/rc/prompt.c @@ -6,11 +6,11 @@ prompt(ushort *flag) int f = *flag; if(f){ if(!readline("> ")){ - proc->flag.eof = 1; + runner->flag.eof = 1; return 0; } - proc->line++; + runner->line++; *flag = 0; } return 1; diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h index 9c6307f..ef7c18e 100644 --- a/sys/cmd/rc/rc.h +++ b/sys/cmd/rc/rc.h @@ -93,6 +93,22 @@ struct Redir struct Redir *link; /* what else to do (reverse order) */ }; +enum +{ + PNil, + PRun, + PStop, + PSig, + PAgain, + PDone, +}; + +struct WaitItem +{ + int pid; + ushort status; +}; + struct Thread { struct { @@ -109,21 +125,19 @@ struct Thread Redir *redir; // list of redirections struct { - ushort i : 1; - ushort eof : 1; - ushort stop : 1; - ushort done : 1; - ushort again : 1; - } flag; // flags for process + ushort i : 1; + ushort eof : 1; + } flag; struct { - int len, cap, *pid; + ushort status; + int len, cap; + struct WaitItem *on; } wait; int pid, pgid, status; long line; - Tree *nodes; // memory allocation Thread *link; // process we return to Thread *next; // next job }; @@ -131,6 +145,7 @@ struct Thread struct Shell { int pid; + Io *err; int status; int interactive; Thread *jobs; @@ -140,9 +155,7 @@ struct Shell // globals extern Shell shell; - -extern Thread *proc; -extern Io *errio; +extern Thread *runner; extern Code *compiled; // ----------------------------------------------------------------------- @@ -203,6 +216,7 @@ void killzombies(void); Thread *getjob(int, int*); void addjob(Thread *); void deljob(Thread *); +void wakeup(Thread *); void report(Thread *, int); void foreground(Thread *, int); diff --git a/sys/cmd/rc/syntax.y b/sys/cmd/rc/syntax.y index 247cc8a..a580cb0 100644 --- a/sys/cmd/rc/syntax.y +++ b/sys/cmd/rc/syntax.y @@ -2,11 +2,13 @@ %token Targs %token Tbasic Tparen Tblock +%define parse.error verbose + %{ #include "rc.h" int yylex(void); - void yyerror(char *); + void yyerror(const char *); %} /* operator precendence: lowest first */ @@ -67,6 +69,7 @@ cmd: /* empty */ %prec Twhile { $$ = nil; } | basic { $$ = maketree1(Tbasic, $1); } | block +| assign cmd %prec Tbang { $$ = hangchild1($1, $2, 2); } | Tif paren nl ifbody { $$ = hangchild1($2, $1, 0); } basic: diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c index 7b5d75a..5e1e90c 100644 --- a/sys/cmd/rc/var.c +++ b/sys/cmd/rc/var.c @@ -159,7 +159,7 @@ globalvar(char *name) h = hash(name, arrlen(globals)); if(strcmp(name,"PATH")==0){ - flush(errio); + flush(shell.err); } for(v = globals[h]; v; v = v->link){ @@ -175,8 +175,8 @@ Var* var(char *name) { Var *v; - if(proc){ - for(v = proc->local; v; v=v->link) + if(runner){ + for(v = runner->local; v; v=v->link) if(strcmp(v->name, name) == 0) return v; } @@ -206,7 +206,7 @@ mkenv(void) nchr+=strlen(a->str)+1; \ } - for(v= proc->local; v; v=v->link){ + for(v= runner->local; v; v=v->link){ BODY } for(h=globals; h!=arrend(globals); h++){ @@ -238,7 +238,7 @@ mkenv(void) *p++='\0'; \ } - for(v=proc->local; v; v=v->link){ + for(v=runner->local; v; v=v->link){ BODY } for(h=globals; h!=arrend(globals); h++){ @@ -265,7 +265,7 @@ initpath(void) v = globalvar("PATH"); v->update = bigpath; - flush(errio); + flush(shell.err); bigpath(v); } diff --git a/sys/cmd/rc/wait.c b/sys/cmd/rc/wait.c index db586cb..44ffb58 100644 --- a/sys/cmd/rc/wait.c +++ b/sys/cmd/rc/wait.c @@ -8,13 +8,11 @@ struct WaitMsg { int pid; + int type; ulong time[3]; int status; - int signal; - int suspend; }; - // ----------------------------------------------------------------------- // internal @@ -30,7 +28,7 @@ await(int pid4, int opt, struct WaitMsg *msg) for(;;){ if((pid = wait4(pid4, &status, opt, &ru)) <= 0){ msg->pid = 0; - perror("failed wait"); + perror("failed wait4"); return 0; } @@ -43,8 +41,7 @@ await(int pid4, int opt, struct WaitMsg *msg) msg->time[1] = s; msg->time[2] = u+s; msg->status = WEXITSTATUS(status); - msg->signal = 0; - msg->suspend = 0; + msg->type = PDone; return 1; } @@ -55,8 +52,7 @@ await(int pid4, int opt, struct WaitMsg *msg) msg->time[1] = s; msg->time[2] = u+s; msg->status = WCOREDUMP(status); - msg->signal = 1; - msg->suspend = 0; + msg->type = PSig; return 1; } @@ -67,14 +63,27 @@ await(int pid4, int opt, struct WaitMsg *msg) msg->time[1] = s; msg->time[2] = u+s; msg->status = WSTOPSIG(status); - msg->signal = 0; - msg->suspend = 1; + msg->type = PStop; return 1; } } } +static +int +shouldwait(Thread *job) +{ + int i; + + for(i=0; iwait.len; i++){ + if(job->wait.on[i].status == PRun) + return 1; + } + + return 0; +} + // ----------------------------------------------------------------------- // exported @@ -90,7 +99,7 @@ havewait(Thread *job, int pid) int i; for(i=0; iwait.len; i++) - if(job->wait.pid[i] == pid) + if(job->wait.on[i].pid == pid) return 1; return 0; } @@ -100,9 +109,10 @@ addwait(Thread *job, int pid) { if(job->wait.len == job->wait.cap){ job->wait.cap = job->wait.cap + 2; - job->wait.pid = erealloc(job->wait.pid, job->wait.cap*sizeof(*job->wait.pid)); + job->wait.on = erealloc(job->wait.on, job->wait.cap*sizeof(*job->wait.on)); } - job->wait.pid[job->wait.len++] = pid; + + job->wait.on[job->wait.len++] = (struct WaitItem){.pid=pid, .status=PRun}; } void @@ -111,8 +121,8 @@ delwait(Thread *job, int pid) int r, w; for(r=w=0; r < job->wait.len; r++){ - if(job->wait.pid[r] != pid) - job->wait.pid[w++] = job->wait.pid[r]; + if(job->wait.on[r].pid != pid) + job->wait.on[w++].pid = job->wait.on[r].pid; } job->wait.len = w; } @@ -120,36 +130,63 @@ delwait(Thread *job, int pid) int waitall(Thread *job) { + int i; Thread *t; struct WaitMsg msg; - while(job->wait.len && await(-job->pgid, WUNTRACED, &msg)){ - if(msg.pid == 0 && errno == ECHILD){ + while(shouldwait(job) && await(-job->pgid, WUNTRACED, &msg)){ + if(msg.pid == 0){ perror("wait job"); return 0; } + for(i=0; i < job->wait.len; i++){ + if(job->wait.on[i].pid == msg.pid){ + switch(msg.type){ + case PStop: + print(shell.err, "%d: suspended\n", msg.pid); + job->wait.status = PStop; + job->wait.on[i].status = PStop; + break; + + case PSig: + print(shell.err, "%d: terminated by signal %d\n", msg.pid, msg.status); + /* fallthrough */ + case PDone: + job->wait.on[i].status = PDone; + delwait(job, msg.pid); + if(!job->wait.len) + job->wait.status = PDone; + break; + + default: + fatal("%d: unrecognized message type %d\n", msg.pid, msg.type); + } + break; + } + } + } +#if 0 for(t=job; t; t=t->link){ if(t->pid == msg.pid){ t->status = msg.status; - t->flag.stop = t->flag.done = t->flag.again = 0; if(msg.suspend){ t->flag.stop = 1; }else{ t->flag.done = 1; if(msg.signal){ - print(errio, "%d: terminated by signal %d\n", msg.pid, msg.status); + print(shell.err, "%d: terminated by signal %d\n", msg.pid, msg.status); } } delwait(t, msg.pid); goto outer; } } - perror("waitpid"); return 0; outer:; } +#endif return 1; } @@ -161,24 +198,21 @@ killzombies(void) int index, status, pid; while((pid=waitpid(-1, &status, WNOHANG))>0){ - print(errio, "pid %d\n", pid); - flush(errio); + print(shell.err, "found zombie pid %d\n", pid); + flush(shell.err); job = getjob(pid, &index); - if(!job){ + if(!job) perror("invalid pid"); - } - - job->flag.done = job->flag.stop = job->flag.again = 0; if(WIFEXITED(status)) - job->flag.done = 1; + job->wait.status = PDone; if(WIFSTOPPED(status)) - job->flag.stop = 1; + job->wait.status = PStop; if(WIFCONTINUED(status)) - job->flag.again = 1; + job->wait.status = PAgain; - if(job->flag.done){ + if(job->wait.status == PDone){ report(job,index); deljob(job); } -- cgit v1.2.1