in a few cases, such as with python threading, ape programs end up waiting for children in both parent and child after rfork(RFMEM|RFPROC). thus the list of procs returned by wait which are set aside must be locked, and the pid receiving the wait message must be recorded so that both parent and child will only get wait messages for their own children. Reference: /n/atom/patch/applied2013/apewaitrfmem Date: Wed Sep 25 23:41:47 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/ape/lib/ap/plan9/wait.c Wed Sep 25 23:39:30 2013 +++ /sys/src/ape/lib/ap/plan9/wait.c Sun Oct 20 18:53:31 2013 @@ -10,30 +10,42 @@ #include #include "sys9.h" #include "dir.h" +#include "qlock.h" /* - * status not yet collected for processes that have exited + * status not yet collected for processes that have exited. + * use a lock, and record the original pid of the process recording + * the wait message, in case of rfork(RFMEM|RFPROC) which + * is used to simulate threads. */ typedef struct Waited Waited; struct Waited { + int ppid; Waitmsg* msg; Waited* next; }; +static QLock wdlk; static Waited *wd; static Waitmsg * lookpid(int pid) { + int mypid; Waited **wl, *w; Waitmsg *msg; + mypid = getpid(); + qlock(&wdlk); for(wl = &wd; (w = *wl) != nil; wl = &w->next) + if(mypid == w->ppid) if(pid <= 0 || w->msg->pid == pid){ msg = w->msg; *wl = w->next; + qunlock(&wdlk); free(w); return msg; } + qunlock(&wdlk); return 0; } @@ -48,9 +60,12 @@ free(msg); return; } + w->ppid = getpid(); w->msg = msg; + qlock(&wdlk); w->next = wd; wd = w; + qunlock(&wdlk); } static int @@ -126,16 +141,16 @@ 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){ + for(;;){ + 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); - return 0; } - free(d); - } - for(;;){ w = _WAIT(); if(w == nil){ _syserrno();