From ead340a66039096c7b4bf12dcd65e189769c6653 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Mon, 18 Oct 2021 17:51:11 -0700 Subject: feat(rc): job control prototype working for basic commands --- sys/cmd/rc/exec.c | 244 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 169 insertions(+), 75 deletions(-) (limited to 'sys/cmd/rc/exec.c') diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c index 868b1dc..80cd645 100644 --- a/sys/cmd/rc/exec.c +++ b/sys/cmd/rc/exec.c @@ -16,21 +16,12 @@ struct Builtin{ static Word nullpath = { .str="", .link=nil }; struct Builtin builtin[]={ - {".", xdot}, + {".", xdot}, + {"fg", xfg}, + {"jobs", xjob}, 0, }; -/* stub out until we need */ -void Xasync(void){} -void Xconcatenate(void){} -void Xexit(void){} -void Xfunc(void){} -void Xfor(void){} -void Xglob(void){} -void Xjump(void){} -void Xmatch(void){} -void Xpipe(void){} -void Xread(void){} // ----------------------------------------------------------------------- // internal @@ -40,10 +31,10 @@ static void pushword(char *str) { - if(!shell->args) - fatal("attempt to push on empty argument stack"); + if(!proc->args) + fatal("attempt to push on empty argument stack\n"); - shell->args->word = makeword(str, shell->args->word); + proc->args->word = makeword(str, proc->args->word); } static @@ -51,14 +42,14 @@ void popword(void) { Word *w; - if(!shell->args) - fatal("tried to pop word on empty argument stack"); + if(!proc->args) + fatal("tried to pop word on empty argument stack\n"); - w = shell->args->word; + w = proc->args->word; if(!w) - fatal("tried to pop word but nothing there"); + fatal("tried to pop word but nothing there\n"); - shell->args->word = w->link; + proc->args->word = w->link; efree(w->str); efree(w); } @@ -110,21 +101,21 @@ pushlist(void) List *stack = emalloc(sizeof(*stack)); stack->word = nil; - stack->link = shell->args; + stack->link = proc->args; - shell->args = stack; + proc->args = stack; } static void poplist(void) { - List *stack = shell->args; + List *stack = proc->args; if(!stack) - fatal("attempted to pop an empty argument stack"); + fatal("attempted to pop an empty argument stack\n"); freelist(stack->word); - shell->args = stack->link; + proc->args = stack->link; efree(stack); } @@ -149,12 +140,12 @@ void xx(void) { popword(); // "exec" - if(!shell->args->word){ + if(!proc->args->word){ Xerror("empty argument list"); return; } - execute(shell->args->word, path(shell->args->word->str)); + execute(proc->args->word, path(proc->args->word->str)); poplist(); } @@ -169,13 +160,38 @@ xforkx(void) case -1: return -1; case 0: // child - clearwait(); + clearwait(proc); + + if(shell.interactive){ + proc->pid = getpid(); + if(proc->pgid <= 0) + proc->pgid = proc->pid; + + setpgid(pid, proc->pgid); + tcsetpgrp(0, proc->pgid); + + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGTTIN, SIG_DFL); + signal(SIGTTOU, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + } + pushword("exec"); xx(); - exit(1); + + exit(1); // NOTE: xx does not return! /*unreachable*/ - default: - addwait(pid); + default: // parent + addwait(proc, pid); + + /* ensure the state matches for parent and child */ + proc->pid = pid; + if(proc->pgid <= 0) + proc->pgid = pid; + setpgid(pid, proc->pgid); + return pid; } } @@ -189,9 +205,9 @@ pushredir(int type, int from, int to) r->type = type; r->from = from; r->to = to; - r->link = shell->redir; + r->link = proc->redir; - shell->redir = r; + proc->redir = r; } /* byte code */ @@ -209,9 +225,11 @@ run(Code *c, int pc, Var *local) new->cmd.io = nil; new->flag.eof = 0; new->line = 1; - new->link = shell; + new->link = proc; + + new->pgid = new->pid = -1; - shell = new; + proc = new; } // ----------------------------------------------------------------------- @@ -281,23 +299,22 @@ xdot(void) Thread *old; char file[512]; - old = shell; popword(); #if 0 - if(old->args->word && strcmp(old->args->word->str, "-i")==0){ + if(proc->args->word && strcmp(proc->args->word->str, "-i")==0){ iflag = 1; popword(); } #endif /* get input file */ - if(!old->args->word){ + if(!proc->args->word){ Xerror("usage: . [-i] file [arg ...]\n"); return; } - base = strdup(old->args->word->str); + base = strdup(proc->args->word->str); popword(); - for(fd=-1, p=path(base); p ; p = p->link){ + for(fd=-1, p=path(base); p; p = p->link){ strcpy(file, p->str); if(file[0]) @@ -315,15 +332,17 @@ xdot(void) return; } /* set up for a new command loop */ + old = proc; // store pointer to old code run(dotcmd, 1, nil); - pushredir(Rclose, fd, 0); - shell->cmd.path = base; - shell->cmd.io = openfd(fd); + /* operations on new command stack */ + pushredir(Rclose, fd, 0); + proc->cmd.path = base; + proc->cmd.io = openfd(fd); /* push $* value */ pushlist(); - shell->args->word = old->args->word; + proc->args->word = old->args->word; /* free caller's copy of $* */ argv = old->args; @@ -336,6 +355,50 @@ xdot(void) //ndot++; } +void +xjob(void) +{ + int i; + Thread *job; + + for(i = 0, job = shell.jobs; job; job = job->next) + report(job,i); + + poplist(); +} + +void +xfg(void) +{ + int i; + Thread *job, *old; + + popword(); // fg + + /* get input job id */ + if(!proc->args->word){ + print(errio, "usage: fg [pid|\%num]\n"); + poplist(); + return; + } + + i = atoi(proc->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? + foreground(job, 1); + printf("hi\n"); +} + void xboot(int argc, char *argv[]) { @@ -369,10 +432,10 @@ xboot(int argc, char *argv[]) for(i = argc-1; i > 0; --i) pushword(argv[i]); - /* interpreter loop */ + /* main interpreter loop */ for(;;){ - shell->code.i++; - (*shell->code.exe[shell->code.i-1].f)(); + proc->code.i++; + (*proc->code.exe[proc->code.i-1].f)(); } } @@ -390,31 +453,50 @@ Xerror(char *msg) { print(errio, "rc: %s", msg); flush(errio); - while(!shell->flag.i) + while(!proc->flag.i) Xreturn(); } void Xreturn(void) { - Thread *run = shell; + Thread *run = proc; + + /* + * 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){ + run->code.i--; + proc = run->link; + return; + } - printf("returning\n"); + /* + * If our job has finished: + * 1. remove from our list + * 2. clean up its memory! + */ + if(run->flag.done) + deljob(run); while(run->args) poplist(); freecode(run->code.exe); + efree(run->wait.pid); - shell = run->link; + proc = run->link; efree(run); - if(!shell) + if(!proc) exit(0); } void Xword(void) { - pushword(shell->code.exe[shell->code.i++].s); + pushword(proc->code.exe[proc->code.i++].s); } void @@ -424,18 +506,18 @@ Xdollar(void) char *s, *t; Word *a, *star; - if(count(shell->args->word)!=1){ + if(count(proc->args->word)!=1){ Xerror("variable name not singleton!\n"); return; } - s = shell->args->word->str; + s = proc->args->word->str; // deglob(s); n = 0; for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; - a = shell->args->link->word; + a = proc->args->link->word; if(n==0 || *t) a = copywords(var(s)->val, a); @@ -450,7 +532,7 @@ Xdollar(void) } poplist(); - shell->args->word = a; + proc->args->word = a; } void @@ -458,22 +540,22 @@ Xassign(void) { Var *v; - if(count(shell->args->word)!=1){ + if(count(proc->args->word)!=1){ Xerror("variable name not singleton!\n"); return; } //deglob(runq->argv->words->word); - v = var(shell->args->word->str); + v = var(proc->args->word->str); poplist(); //globlist(); freewords(v->val); - v->val = shell->args->word; + v->val = proc->args->word; v->new = 1; if(v->update) v->update(v); - shell->args->word = nil; + proc->args->word = nil; poplist(); } @@ -485,7 +567,7 @@ Xreadcmd(void) Word *prompt; flush(errio); - root = shell; + root = proc; if(yyparse()){ exit(1); @@ -494,21 +576,22 @@ Xreadcmd(void) run(compiled, 1, root->local); } + // killzombies(); freeparsetree(); } void Xlocal(void) { - if(count(shell->args->word)!=1){ + if(count(proc->args->word)!=1){ Xerror("variable name must be singleton\n"); return; } //deglob(shell->args->word->str); - shell->local = makevar(strdup(shell->args->word->str), shell->local); - shell->local->val = copywords(shell->args->link->word, nil); - shell->local->new = 1; + proc->local = makevar(strdup(proc->args->word->str), proc->local); + proc->local->val = copywords(proc->args->link->word, nil); + proc->local->new = 1; poplist(); poplist(); @@ -517,13 +600,13 @@ Xlocal(void) void Xunlocal(void) { - Var *v = shell->local, *hide; + Var *v = proc->local, *hide; if(!v) - fatal("Xunlocal: no locals!", 0); + fatal("Xunlocal: no locals!\n", 0); printf("unlocal\n"); - shell->local = v->link; + proc->local = v->link; hide = var(v->name); hide->new = 1; @@ -540,12 +623,12 @@ Xbasic(void) int pid, status; struct Builtin *b; - arg = shell->args->word; + arg = proc->args->word; if(!arg){ Xerror("empty argument list\n"); return; } - print(errio, "recieved arg: %v\n", arg); // for debugging + /* print(errio, "recieved arg: %v\n", arg); // for debugging */ flush(errio); v = var(arg->str); @@ -561,6 +644,10 @@ Xbasic(void) } } + /* if we are here then it's an external command */ + killzombies(); + addjob(proc); + // run the external command if((pid = xforkx()) < 0) { Xerror("try again"); @@ -568,9 +655,16 @@ Xbasic(void) } poplist(); - do{ - waitpid(pid, &status, 0); - } while(!WIFEXITED(status) && !WIFSIGNALED(status)); - printf("done waiting\n"); + if(!shell.interactive) + waitall(proc); + + foreground(proc, 0); // waits for child } + +void +Xexit(void) +{ + exit(shell.status); +} + -- cgit v1.2.1