fixed many things, including a memory leak. it doesn't forget about previously seen pids if WNOHANG set. it doesn't hang in some cases when WNOHANG set. it returns status correctly for things it has put on the list. it handles pid 0 consistently (posix says same process group; here it has always been equivalent to -1,except in the wait4 version one part did and another didn't) it now fills in a struct rusage if provided (though most of it is zero). it should be easier to follow: see if there is a wait record already; if not and WNOHANG set, see if wait will not block (if it will, return); otherwise wait for the pid requested and enlist all wait records that do not match; set optional status and rusage; free the record and return pid. its source format is more plan 9-ish. i've added struct rusage to sys/resource.h, and in sys/wait.h made the declarations of wait4 and rusage conditional on _BSD_EXTENSION, and wait4 says struct rusage* not void* Unix has indeed got very smelly. according to linux lists, posix is going to add another wait variant, so watch this space ... i can't wait. Reference: /n/sources/patch/applied/apewait Date: Tue Aug 31 21:33:05 CES 2004 --- /sys/include/ape/sys/wait.h Tue Aug 31 21:33:06 2004 +++ /sys/include/ape/sys/wait.h Tue Aug 31 21:33:06 2004 @@ -20,8 +20,11 @@ pid_t wait(int *); pid_t waitpid(pid_t, int *, int); -pid_t wait3(int *, int, void *); -pid_t wait4(pid_t, int *, int, void *); +#ifdef _BSD_EXTENSION +struct rusage; +pid_t wait3(int *, int, struct rusage *); +pid_t wait4(pid_t, int *, int, struct rusage *); +#endif #ifdef __cplusplus } --- /sys/include/ape/sys/resource.h Tue Aug 31 21:33:06 2004 +++ /sys/include/ape/sys/resource.h Tue Aug 31 21:33:05 2004 @@ -5,6 +5,25 @@ This header file is an extension to ANSI/POSIX #endif -/* Empty file, included by some X programs */ +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; /* max resident set size */ +#define ru_first ru_ixrss + long ru_ixrss; /* integral shared memory size */ + long ru_idrss; /* integral unshared data " */ + long ru_isrss; /* integral unshared stack " */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +#define ru_last ru_nivcsw +}; #endif /* !__RESOURCE_H__ */ --- /sys/src/ape/lib/ap/plan9/wait.c Tue Aug 31 21:33:06 2004 +++ /sys/src/ape/lib/ap/plan9/wait.c Tue Aug 31 21:33:06 2004 @@ -1,134 +1,150 @@ #include "lib.h" #include #include +#include +#include #include #include +#include #include #include #include "sys9.h" +#include "dir.h" /* -** PID cache -*/ -typedef struct wdesc wdesc; -struct wdesc { - pid_t w_pid; - Waitmsg *w_msg; - wdesc *w_next; + * status not yet collected for processes that have exited + */ +typedef struct Waited Waited; +struct Waited { + Waitmsg* msg; + Waited* next; }; -static wdesc *wd = 0; +static Waited *wd; static Waitmsg * -lookpid (pid_t pid) { - wdesc **wp0 = &wd, *wp; +lookpid(int pid) +{ + Waited **wl, *w; Waitmsg *msg; - if (pid == -1) { - if (wd == 0) - return 0; - pid = wd->w_pid; - } - for (wp = wd; wp; wp = wp->w_next) { - if (wp->w_pid == pid) { - msg = wp->w_msg; - *wp0 = wp->w_next; - free (wp); + 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; } - wp0 = &(wp->w_next); - } return 0; } static void -addpid (Waitmsg *msg) { - wdesc *wp = malloc (sizeof (wdesc)); +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; +} - wp->w_msg = msg; - wp->w_pid = msg->pid; - wp->w_next = wd; - wd = wp; +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, 0); +wait(int *status) +{ + return wait4(-1, status, 0, nil); } pid_t -waitpid (pid_t wpid, int *status, int options) { - return wait4(wpid, status, options, 0); +waitpid(pid_t wpid, int *status, int options) +{ + return wait4(wpid, status, options, nil); } pid_t -wait3 (int *status, int options, Waitmsg *waitmsg) { - return wait4(-1, status, options, waitmsg); +wait3(int *status, int options, struct rusage *res) +{ + return wait4(-1, status, options, res); } pid_t -wait4 (pid_t wpid, int *status, int options, Waitmsg *waitmsg) { +wait4(pid_t wpid, int *status, int options, struct rusage *res) +{ + char pname[50]; + Dir *d; Waitmsg *w; - if (options & WNOHANG) { - char pname[128]; - int i; - struct stat buf; - - snprintf (pname, sizeof (pname), "/proc/%d/wait", getpid()); - i = stat (pname, &buf); - if (i >= 0 && buf.st_size == 0) - return 0; - } - if (w = lookpid (wpid)) { - waitmsg = w; - wpid = w->pid; - return wpid; - } - w = _WAIT(); - while (w) { - if (wpid <= 0) { - waitmsg = w; - wpid = w->pid; - if(status) - *status = 0; - return wpid; + 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); } - if (w->pid == wpid) { - if (status) { - int r = 0; - int t = 0; - char *bp, *ep; - - 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; - } - } - *status = (r << 8) | t; + for(;;){ + w = _WAIT(); + if(w == nil){ + _syserrno(); + return -1; } - waitmsg = w; - wpid = w->pid; - return wpid; - } else { - addpid (w); + if(wpid <= 0 || w->pid == wpid) + break; + addpid(w); } - w = _WAIT(); - } - if (w == 0) { - _syserrno (); } + if(res != nil) + waitresource(res, w); + if(status != nil) + *status = waitstatus(w); + wpid = w->pid; + free(w); + return wpid; }