#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){ 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 = WCOREDUMP(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; } // ----------------------------------------------------------------------- // 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)){ 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; if(msg.suspend){ t->flag.stop = 1; }else{ t->flag.done = 1; if(msg.signal){ 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; } 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); } } } #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