ref: 04c3a6f66e3b895a087124ed415f01e23e21ee10
dir: /sys/src/ape/lib/ap/plan9/wait.c/
#include "lib.h" #include <stdlib.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <stdio.h> #include "sys9.h" #include "dir.h" /* * status not yet collected for processes that have exited */ typedef struct Waited Waited; struct Waited { Waitmsg* msg; Waited* next; }; static Waited *wd; static Waitmsg * lookpid(int pid) { Waited **wl, *w; Waitmsg *msg; for(wl = &wd; (w = *wl) != nil; wl = &w->next) if(pid <= 0 || w->msg->pid == pid){ msg = w->msg; *wl = w->next; free(w); return msg; } return 0; } static void addpid(Waitmsg *msg) { Waited *w; w = malloc(sizeof(*w)); if(w == nil){ /* lost it; what can we do? */ free(msg); return; } w->msg = msg; w->next = wd; wd = w; } static int waitstatus(Waitmsg *w) { int r, t; char *bp, *ep; r = 0; t = 0; if(w->msg[0]){ /* message is 'prog pid:string' */ bp = w->msg; while(*bp){ if(*bp++ == ':') break; } if(*bp == 0) bp = w->msg; r = strtol(bp, &ep, 10); if(*ep == 0){ if(r < 0 || r >= 256) r = 1; }else{ t = _stringsig(bp); if(t == 0) r = 1; } } return (r<<8) | t; } static void waitresource(struct rusage *ru, Waitmsg *w) { memset(ru, 0, sizeof(*ru)); ru->ru_utime.tv_sec = w->time[0]/1000; ru->ru_utime.tv_usec = (w->time[0]%1000)*1000; ru->ru_stime.tv_sec = w->time[1]/1000; ru->ru_stime.tv_usec = (w->time[1]%1000)*1000; } pid_t wait(int *status) { return wait4(-1, status, 0, nil); } pid_t waitpid(pid_t wpid, int *status, int options) { return wait4(wpid, status, options, nil); } pid_t wait3(int *status, int options, struct rusage *res) { return wait4(-1, status, options, res); } pid_t wait4(pid_t wpid, int *status, int options, struct rusage *res) { char pname[50]; Dir *d; Waitmsg *w; w = lookpid(wpid); if(w == nil){ if(options & WNOHANG){ snprintf(pname, sizeof(pname), "/proc/%d/wait", getpid()); d = _dirstat(pname); if(d != nil && d->length == 0){ free(d); return 0; } free(d); } for(;;){ w = _WAIT(); if(w == nil){ _syserrno(); return -1; } if(wpid <= 0 || w->pid == wpid) break; addpid(w); } } if(res != nil) waitresource(res, w); if(status != nil) *status = waitstatus(w); wpid = w->pid; free(w); return wpid; }