From 2b53bca326decd50012883f0cff3b5316a3e100d Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 19 Oct 2021 13:28:01 -0700 Subject: feat(rc): prototype of async jobs --- sys/cmd/rc/exec.c | 112 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 32 deletions(-) (limited to 'sys/cmd/rc/exec.c') diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c index 87b6bb7..37c289b 100644 --- a/sys/cmd/rc/exec.c +++ b/sys/cmd/rc/exec.c @@ -135,6 +135,31 @@ path(char *w) return path; } +static inline +void +defaultsignal(void) +{ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGTTIN, SIG_DFL); + signal(SIGTTOU, SIG_DFL); + signal(SIGCHLD, SIG_DFL); +} + +static inline +void +setpid(int pid) +{ + runner->pid = pid; + if(runner->pgid <= 0){ + runner->pgid = runner->pid; + addjob(runner); + } + + setpgid(pid, runner->pgid); +} + static void xx(void) @@ -161,21 +186,12 @@ xforkx(void) return -1; case 0: // child clearwait(runner); + runner->link = nil; if(shell.interactive){ - runner->pid = getpid(); - if(runner->pgid <= 0) - runner->pgid = runner->pid; - - setpgid(pid, runner->pgid); + setpid(getpid()); tcsetpgrp(0, runner->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); + defaultsignal(); } pushword("exec"); @@ -185,12 +201,7 @@ xforkx(void) /*unreachable*/ default: // parent addwait(runner, pid); - - /* ensure the state matches for parent and child */ - runner->pid = pid; - if(runner->pgid <= 0) - runner->pgid = pid; - setpgid(pid, runner->pgid); + setpid(pid); // ensure the state matches for parent and child return pid; } @@ -213,7 +224,7 @@ pushredir(int type, int from, int to) /* byte code */ static void -run(Code *c, int pc, Var *local) +run(Code *c, int pc, Var *local, int keeppid) { Thread *new = emalloc(sizeof(*new)); @@ -236,7 +247,10 @@ run(Code *c, int pc, Var *local) new->wait.on = nil; new->status = 0; - new->pgid = new->pid = -1; + if(keeppid) + new->pgid = runner->pgid, new->pid = runner->pid; + else + new->pgid = new->pid = -1; new->line = 0; new->link = runner; @@ -285,9 +299,9 @@ count(Word *w) // ----------------------------------------------------------------------- // builtins -static Code dotcmd[14] = +static Code dotcmd[14] = { - [0] = {.i = 1}, + [0] = {.i = 0}, [1] = {.f = Xmark}, [2] = {.f = Xword}, [3] = {.s = "0"}, @@ -346,7 +360,7 @@ xdot(void) } /* set up for a new command loop */ old = runner; // store pointer to old code - run(dotcmd, 1, nil); + run(dotcmd, 1, nil, 0); /* operations on new command stack */ pushredir(Rclose, fd, 0); @@ -434,7 +448,7 @@ xboot(int argc, char *argv[]) bootstrap[i++].f = Xexit; bootstrap[i].i = 0; - run(bootstrap, 1, nil); + run(bootstrap, 1, nil, 0); pushlist(); // prime bootstrap argv argv0 = strdup(argv[0]); @@ -478,7 +492,7 @@ Xreturn(void) * 2. return to our calling thread * 3. don't free! */ - case PStop: + case Prun: case Pstop: run->code.i--; runner = run->link; return; @@ -487,7 +501,7 @@ Xreturn(void) * 1. remove from our list * 2. continue to clean up its memory */ - case PDone: + case Pdone: deljob(run); /* fallthrough */ default: @@ -589,7 +603,7 @@ Xreadcmd(void) --root->code.i; }else{ --root->code.i; /* re-execute Xreadcmd after codebuf runs */ - run(compiled, 1, root->local); + run(compiled, 1, root->local, 0); } killzombies(); @@ -629,6 +643,43 @@ Xunlocal(void) efree(v); } +void +Xasync(void) +{ + int pid; + int null = open("/dev/null", 0); + if(!null){ + Xerror("can not open /dev/null\n"); + return; + } + + switch(pid=fork()){ + case -1: + close(null); + Xerror("fork failed: try again"); + break; + + case 0: // child + clearwait(runner); + pushredir(Ropen, null, 0); + if(shell.interactive){ // NOTE: this needs to read off its caller's interactivity + setpid(getpid()); + defaultsignal(); + } + run(runner->code.exe, runner->code.i+1, runner->local, 1); + runner->link = nil; + break; + + default: // parent + close(null); + setpid(pid); + addwait(runner, pid); + + runner->code.i = runner->code.exe[runner->code.i].i; /* jump to end of async command */ + /* don't wait: continue running */ + } +} + void Xbasic(void) { @@ -642,7 +693,6 @@ Xbasic(void) Xerror("empty argument list\n"); return; } - flush(shell.err); v = var(arg->str); if(v->func){ @@ -658,7 +708,6 @@ Xbasic(void) } /* if we are here then it's an external command */ - addjob(runner); // run the external command if((pid = xforkx()) < 0) { @@ -666,12 +715,11 @@ Xbasic(void) return; } - poplist(); - if(!shell.interactive) waitall(runner); foreground(runner, 0); // waits for child + poplist(); } void @@ -735,5 +783,5 @@ Xflat(void) void Xexit(void) { - exit(shell.status); + exit(runner->status); } -- cgit v1.2.1