From ce05175372a9ddca1a225db0765ace1127a39293 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 12 Nov 2021 09:22:01 -0800 Subject: chore: simplified organizational structure --- src/cmd/rc/wait.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 src/cmd/rc/wait.c (limited to 'src/cmd/rc/wait.c') diff --git a/src/cmd/rc/wait.c b/src/cmd/rc/wait.c new file mode 100644 index 0000000..911601c --- /dev/null +++ b/src/cmd/rc/wait.c @@ -0,0 +1,247 @@ +#include "rc.h" + +#include + +// ----------------------------------------------------------------------- +// globals + +struct WaitMsg +{ + int pid; + int type; + ulong time[3]; + int status; +}; + +// ----------------------------------------------------------------------- +// 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){ + if(errno == ECHILD){ + msg->pid = -1; + return 1; + } + msg->pid = 0; + perror("failed wait4"); + 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->type = Pdone; + + return 1; + } + + if(WIFSIGNALED(status)){ + msg->pid = pid; + msg->time[0] = u; + msg->time[1] = s; + msg->time[2] = u+s; + msg->status = WTERMSIG(status); + msg->type = Psig; + + 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->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; +} + +static inline +void +notify(Thread *job, struct WaitMsg msg) +{ + int i; + for(i=0; i < job->wait.len; i++){ + if(job->wait.on[i].pid == msg.pid){ + job->status = msg.status; + 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; + } + } +} + +// ----------------------------------------------------------------------- +// 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.on[i].pid == 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.on = erealloc(job->wait.on, job->wait.cap*sizeof(*job->wait.on)); + } + + job->wait.on[job->wait.len++] = (struct WaitItem){.pid=pid, .status=Prun}; +} + +void +delwait(Thread *job, int pid) +{ + int r, w; + + for(r=w=0; r < job->wait.len; r++){ + if(job->wait.on[r].pid != pid) + job->wait.on[w++].pid = job->wait.on[r].pid; + } + job->wait.len = w; +} + +int +waitall(Thread *job) +{ + int i; + Thread *t; + struct WaitMsg msg; + + while(shouldwait(job) && await(-job->pgid, WUNTRACED, &msg)){ + switch(msg.pid){ + case 0: // error + perror("wait job"); + return 0; + case -1: // no children: assume they have exited + job->wait.status = Pdone; + clearwait(job); + return 1; + default: + ; + } + + notify(job, msg); + } + return 1; +} + +int +waitfor(Thread *job, int pid) +{ + int i; + Thread *t; + struct WaitMsg msg; + + while(shouldwait(job) && await(-job->pgid, WUNTRACED, &msg)){ + switch(msg.pid){ + case 0: // error + perror("wait for"); + return 0; + case -1: // no children: assume they have exited + job->wait.status = Pdone; + clearwait(job); + return 1; + default: + ; + } + + notify(job, msg); + /* allow for an early exit */ + if(msg.pid == pid) + return 1; + } + return 1; + +} + +void +killzombies(void) +{ + Thread *job; + int index, status, pid; + + while((pid=waitpid(-1, &status, WNOHANG))>0){ + print(shell.err, "found zombie pid %d\n", pid); + flush(shell.err); + + job = getjob(pid, &index); + if(!job) + perror("invalid pid"); + + if(WIFEXITED(status)) + job->wait.status = Pdone; + if(WIFSTOPPED(status)) + job->wait.status = Pstop; + if(WIFCONTINUED(status)) + job->wait.status = Pagain; + + if(job->wait.status == Pdone){ + report(job,index); + deljob(job); + } + } +} -- cgit v1.2.1