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/dwm/config.h | 1 + sys/cmd/rc/code.c | 16 ++-- sys/cmd/rc/exec.c | 244 +++++++++++++++++++++++++++++++++++---------------- sys/cmd/rc/exec.h | 11 +-- sys/cmd/rc/input.c | 14 +-- sys/cmd/rc/lex.c | 6 +- sys/cmd/rc/main.c | 74 ++++++++++------ sys/cmd/rc/prompt.c | 4 +- sys/cmd/rc/rc.h | 65 ++++++++++---- sys/cmd/rc/rules.mk | 2 + sys/cmd/rc/sys.c | 47 ---------- sys/cmd/rc/var.c | 8 +- sys/cmd/rc/wait.c | 210 ++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 507 insertions(+), 195 deletions(-) (limited to 'sys') diff --git a/sys/cmd/dwm/config.h b/sys/cmd/dwm/config.h index ebf7b89..a24bcc7 100644 --- a/sys/cmd/dwm/config.h +++ b/sys/cmd/dwm/config.h @@ -32,6 +32,7 @@ static Rule rules[] = { /* class instance title tags mask isfloating isterminal noswallow monitor */ { "Gimp", nil, nil, 0, 1, 0, 0, -1 }, { "Inkscape", nil, nil, 0, 1, 0, 0, -1 }, + { "zoom", nil, nil, 0, 1, 0, 0, -1 }, { "qutebrowser", nil, nil, 0, 0, 0, 0, -1 }, { "term-256color", nil, nil, 0, 0, 1, -1, -1 }, }; diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c index 6deed89..8dec021 100644 --- a/sys/cmd/rc/code.c +++ b/sys/cmd/rc/code.c @@ -13,9 +13,9 @@ struct Interpreter Code *compiled = nil; static struct Interpreter interpreter; -#define emiti(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].i = (x), interpreter.i++) -#define emitf(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].f = (x), interpreter.i++) -#define emits(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].s = (x), interpreter.i++) +#define emiti(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].i = (x), interpreter.i++) +#define emitf(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].f = (x), interpreter.i++) +#define emits(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].s = (x), interpreter.i++) static int @@ -59,18 +59,21 @@ walk(Tree *node) emitf(Xdollar); break; +#if 0 case '&': emitf(Xasync); p = emiti(0); emitf(Xexit); stashaddr(p); break; +#endif case ';': walk(node->child[0]); walk(node->child[1]); break; +#if 0 case '^': emitf(Xmark); walk(node->child[1]); @@ -78,6 +81,7 @@ walk(Tree *node) walk(node->child[0]); emitf(Xconcatenate); break; +#endif case Targs: walk(node->child[1]); @@ -149,9 +153,11 @@ int compile(Tree *node) { flush(errio); - print(errio, "%t\n", node); + //print(errio, "%t\n", node); + + interpreter.i = 0; + interpreter.code = emalloc(100*sizeof(*interpreter.code)); - interpreter.i = 0; emiti(1); // reference count walk(node); 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); +} + diff --git a/sys/cmd/rc/exec.h b/sys/cmd/rc/exec.h index ef826fb..ad53365 100644 --- a/sys/cmd/rc/exec.h +++ b/sys/cmd/rc/exec.h @@ -7,18 +7,9 @@ * Code in line with jump around {...} */ -void Xasync(void); -void Xconcatenate(void); void Xdollar(void); void Xexit(void); -void Xfunc(void); -void Xfor(void); -void Xglob(void); -void Xjump(void); void Xmark(void); -void Xmatch(void); -void Xpipe(void); -void Xread(void); void Xreturn(void); void Xlocal(void); void Xreadcmd(void); @@ -29,5 +20,7 @@ void Xerror(char*); void Xword(void); /* builtin commands */ +void xfg(void); void xdot(void); +void xjob(void); void xboot(int argc, char *argv[]); diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c index cf05382..4c6b37f 100644 --- a/sys/cmd/rc/input.c +++ b/sys/cmd/rc/input.c @@ -85,7 +85,7 @@ enterraw(int fd) { struct termios raw; - if(!isatty(0)) + if(!shell.interactive) goto fatal; if(!mode.defer) { @@ -995,7 +995,7 @@ notty(void) for(;;){ c = fgetc(stdin); - put(&shell->cmd.io, c); + put(&proc->cmd.io, c); } } @@ -1019,17 +1019,17 @@ readline(char *prompt) int n; // reset the command buffer - shell->cmd.io->e = shell->cmd.io->b = shell->cmd.io->buf; + proc->cmd.io->e = proc->cmd.io->b = proc->cmd.io->buf; - if(!isatty(0)) + if(!shell.interactive) return notty(); - if((n = raw(shell->cmd.io->e, shell->cmd.io->cap-1, prompt)) == -1) + if((n = raw(proc->cmd.io->e, proc->cmd.io->cap-1, prompt)) == -1) return 0; - shell->cmd.io->e += n; + proc->cmd.io->e += n; /* insert a newline character at the end */ - put(&shell->cmd.io, '\n'); + put(&proc->cmd.io, '\n'); printf("\n"); return 1; diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c index ec9e94d..e7c7d7d 100644 --- a/sys/cmd/rc/lex.c +++ b/sys/cmd/rc/lex.c @@ -40,18 +40,18 @@ readc(void) peek = EOF; return c; } - if(shell->flag.eof) + if(proc->flag.eof) return EOF; if(!prompt(&lexer.doprompt)) exit(1); // XXX: hack for signal handling right now... - c = get(shell->cmd.io); + c = get(proc->cmd.io); lexer.doprompt = lexer.doprompt || c=='\n' || c==EOF; if(c==EOF) - shell->flag.eof = 1; + proc->flag.eof = 1; return c; } diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c index 46a4e0f..d1bbd06 100644 --- a/sys/cmd/rc/main.c +++ b/sys/cmd/rc/main.c @@ -2,9 +2,53 @@ #include "parse.h" #include "exec.h" -int rcpid; +#include +#include + +// ----------------------------------------------------------------------- +// globals + Io *errio = nil; -Thread *shell = nil; +Thread *proc = nil; +Shell shell = { 0 }; + +// ----------------------------------------------------------------------- +// functions + +void +initshell(void) +{ + if((shell.interactive=isatty(0))){ + while(tcgetpgrp(0) != (shell.pid = getpgrp())) + kill(-shell.pid, SIGTTIN); + + /* ignore job control signals */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + /* + * NOTE: if SIGCHLD is set to SIG_IGN then + * 1. children that terminate do not become zombies + * 2. call a to wait() will block until all children have terminated + * 3. the call to wait will fail with errno == ECHILD + * see for discussion: + * https://stackoverflow.com/questions/1608017/no-child-process-error-from-waitpid-when-waiting-for-process-group + */ + // signal(SIGCHLD, SIG_IGN); + + /* take control */ + shell.pid = getpid(); + if(setpgid(shell.pid, shell.pid)<0) + fatal("could not put shell in its own process group"); + + tcsetpgrp(0, shell.pid); + } +} + +// ----------------------------------------------------------------------- +// main point of entry int main(int argc, char *argv[]) @@ -17,31 +61,7 @@ main(int argc, char *argv[]) initenv(); initpath(); - - itoa(num, rcpid = getpid()); - setvar("pid", makeword(num, nil)); + initshell(); xboot(argc, argv); -#if 0 - Thread root = { - .cmd = { - .path = "", - .io = openfd(0), - }, - .line = 0, - .flag = { - .i = 1, - .eof = 0, - }, - }; - - shell = &root; - errio = openfd(2); -#if 1 - while(!yyparse()) - ; -#else - printkeycode() -#endif -#endif } diff --git a/sys/cmd/rc/prompt.c b/sys/cmd/rc/prompt.c index b4b1d96..21078e8 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("> ")){ - shell->flag.eof = 1; + proc->flag.eof = 1; return 0; } - shell->line++; + proc->line++; *flag = 0; } return 1; diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h index 1c2aa6b..9c6307f 100644 --- a/sys/cmd/rc/rc.h +++ b/sys/cmd/rc/rc.h @@ -3,6 +3,19 @@ #include #include +/* + * A thread functions much like a GNU job -> it's just a simple execution stack + * We just need to modify the following datastructures: + * + * 1. Need to store the list of all "active" and "foreground" threads + * - Right now we just have Thread *proc which is the running process. + * - Need to move this to a linked list (how does this interact with the link?) + * - Linked list stores the independent roots of each individual process tree + * 2. Child pids are stored inside waitpid right now. Need to associate this more explictly with a thread. + * 3. Wait needs to be generalized to act on threads. + * 4. our "start" function is equivalent to the launch_job function + * 5. running the interpreter runs the launch_process implicitly (with forks called as interpreter functions) + */ // ----------------------------------------------------------------------- // types @@ -14,8 +27,7 @@ typedef struct Tree Tree; typedef struct Redir Redir; typedef union Code Code; typedef struct Thread Thread; - -typedef struct WaitMsg WaitMsg; +typedef struct Shell Shell; struct Io { @@ -86,7 +98,7 @@ struct Thread struct { int i; Code *exe; - } code; // execution stack + } code; // execution stack struct { Io *io; char *path; @@ -97,29 +109,39 @@ struct Thread Redir *redir; // list of redirections struct { - ushort i : 1; - ushort eof : 1; + ushort i : 1; + ushort eof : 1; + ushort stop : 1; + ushort done : 1; + ushort again : 1; } flag; // flags for process - int pid; + struct { + int len, cap, *pid; + } wait; + + int pid, pgid, status; long line; Tree *nodes; // memory allocation Thread *link; // process we return to + Thread *next; // next job }; -struct WaitMsg +struct Shell { - int pid; // of loved one - ulong time[3]; // of loved one & descendants - char *msg; + int pid; + int status; + int interactive; + Thread *jobs; }; // ----------------------------------------------------------------------- // globals -extern int rcpid; -extern Thread *shell; +extern Shell shell; + +extern Thread *proc; extern Io *errio; extern Code *compiled; @@ -168,12 +190,23 @@ void freeparsetree(void); /* sys.c */ void initenv(void); +void execute(Word *, Word*); -void addwait(int); -void clearwait(void); -int waitfor(int); +/* wait.c */ +void addwait(Thread *, int); +void clearwait(Thread*); +int waitall(Thread *); -void execute(Word *, Word*); +void killzombies(void); + +/* job.c */ +Thread *getjob(int, int*); +void addjob(Thread *); +void deljob(Thread *); +void report(Thread *, int); + +void foreground(Thread *, int); +void background(Thread *, int); /* exec.c */ // XXX: odd place for this diff --git a/sys/cmd/rc/rules.mk b/sys/cmd/rc/rules.mk index 44c9b7a..dcddcce 100644 --- a/sys/cmd/rc/rules.mk +++ b/sys/cmd/rc/rules.mk @@ -13,6 +13,8 @@ SRCS_$(d) :=\ $(d)/code.c\ $(d)/var.c\ $(d)/sys.c\ + $(d)/wait.c\ + $(d)/job.c\ $(d)/exec.c\ $(d)/main.c diff --git a/sys/cmd/rc/sys.c b/sys/cmd/rc/sys.c index 2c6a19d..643f327 100644 --- a/sys/cmd/rc/sys.c +++ b/sys/cmd/rc/sys.c @@ -1,12 +1,5 @@ #include "rc.h" -struct Wait -{ - int len, cap, *pid; -}; - -static struct Wait wait; - // ----------------------------------------------------------------------- // internal @@ -71,46 +64,6 @@ initenv(void) } } -void -clearwait(void) -{ - wait.len = 0; -} - -int -havewait(int pid) -{ - int i; - - for(i=0; i= 0 && !havewait(pid)) - return 0; -} -*/ - void execute(Word *cmd, Word *path) { diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c index f0e5f5b..7b5d75a 100644 --- a/sys/cmd/rc/var.c +++ b/sys/cmd/rc/var.c @@ -175,8 +175,8 @@ Var* var(char *name) { Var *v; - if(shell){ - for(v = shell->local; v; v=v->link) + if(proc){ + for(v = proc->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= shell->local; v; v=v->link){ + for(v= proc->local; v; v=v->link){ BODY } for(h=globals; h!=arrend(globals); h++){ @@ -238,7 +238,7 @@ mkenv(void) *p++='\0'; \ } - for(v=shell->local; v; v=v->link){ + for(v=proc->local; v; v=v->link){ BODY } for(h=globals; h!=arrend(globals); h++){ diff --git a/sys/cmd/rc/wait.c b/sys/cmd/rc/wait.c index 06f9614..db586cb 100644 --- a/sys/cmd/rc/wait.c +++ b/sys/cmd/rc/wait.c @@ -1,3 +1,213 @@ #include "rc.h" + #include +// ----------------------------------------------------------------------- +// globals + +struct WaitMsg +{ + int pid; + ulong time[3]; + int status; + int signal; + int suspend; +}; + + +// ----------------------------------------------------------------------- +// internal + +static +int +await(int pid4, int opt, struct WaitMsg *msg) +{ + int pid, status, core; + struct rusage ru; + ulong u, s; + + /* event loop */ + for(;;){ + if((pid = wait4(pid4, &status, opt, &ru)) <= 0){ + msg->pid = 0; + perror("failed wait"); + return 0; + } + + u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000); + s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000); + + if(WIFEXITED(status)){ + msg->pid = pid; + msg->time[0] = u; + msg->time[1] = s; + msg->time[2] = u+s; + msg->status = WEXITSTATUS(status); + msg->signal = 0; + msg->suspend = 0; + + return 1; + } + + if(WIFSIGNALED(status)){ + msg->pid = pid; + msg->time[0] = u; + msg->time[1] = s; + msg->time[2] = u+s; + msg->status = WCOREDUMP(status); + msg->signal = 1; + msg->suspend = 0; + + return 1; + } + + if(WIFSTOPPED(status)){ + msg->pid = pid; + msg->time[0] = u; + msg->time[1] = s; + msg->time[2] = u+s; + msg->status = WSTOPSIG(status); + msg->signal = 0; + msg->suspend = 1; + + return 1; + } + } +} + +// ----------------------------------------------------------------------- +// exported + +void +clearwait(Thread *job) +{ + job->wait.len = 0; +} + +int +havewait(Thread *job, int pid) +{ + int i; + + for(i=0; iwait.len; i++) + if(job->wait.pid[i] == pid) + return 1; + return 0; +} + +void +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.pid[job->wait.len++] = pid; +} + +void +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]; + } + job->wait.len = w; +} + +int +waitall(Thread *job) +{ + Thread *t; + struct WaitMsg msg; + + while(job->wait.len && await(-job->pgid, WUNTRACED, &msg)){ + if(msg.pid == 0 && errno == ECHILD){ + perror("wait job"); + return 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); + } + } + delwait(t, msg.pid); + goto outer; + } + } + + perror("waitpid"); + return 0; + outer:; + } + + return 1; +} + +void +killzombies(void) +{ + Thread *job; + int index, status, pid; + + while((pid=waitpid(-1, &status, WNOHANG))>0){ + print(errio, "pid %d\n", pid); + flush(errio); + + job = getjob(pid, &index); + if(!job){ + perror("invalid pid"); + } + + job->flag.done = job->flag.stop = job->flag.again = 0; + + if(WIFEXITED(status)) + job->flag.done = 1; + if(WIFSTOPPED(status)) + job->flag.stop = 1; + if(WIFCONTINUED(status)) + job->flag.again = 1; + + if(job->flag.done){ + report(job,index); + deljob(job); + } + } +} + +#if 0 +int +waitfor(int pid) +{ + Thread *t; + struct WaitMsg w; + + if(pid >= 0 && !havewait(pid)) + return 0; + + while(await(-proc->pgid, WUNTRACED, &w)){ + delwait(w.pid); + if(w.pid == pid){ + if(w.signal) + print(errio, "pid[%d]: signal: %d\n", w.pid, w.status); + return 1; + } + for(t=proc->link; t; t=t->link){ + if(t->pid == w.pid) + t->pid = -1; + } + } + + return 0; +} +#endif -- cgit v1.2.1