#include <u.h> | |
#include <libc.h> | |
#include <thread.h> | |
typedef struct Waiter Waiter; | |
struct { | |
QLock lk; | |
Waitmsg **msg; | |
int nmsg; | |
int muxer; | |
Waiter *head; | |
} waiting; | |
struct Waiter | |
{ | |
Rendez r; | |
Waitmsg *msg; | |
int pid; | |
Waiter *next; | |
Waiter *prev; | |
}; | |
/* see src/libmux/mux.c */ | |
Waitmsg* | |
procwait(int pid) | |
{ | |
Waiter *w; | |
Waiter me; | |
Waitmsg *msg; | |
int i; | |
memset(&me, 0, sizeof me); | |
me.pid = pid; | |
me.r.l = &waiting.lk; | |
qlock(&waiting.lk); | |
for(i=0; i<waiting.nmsg; i++){ | |
if(waiting.msg[i]->pid == pid){ | |
msg = waiting.msg[i]; | |
waiting.msg[i] = waiting.msg[--waiting.nmsg]; | |
qunlock(&waiting.lk); | |
return msg; | |
} | |
} | |
me.next = waiting.head; | |
me.prev = nil; | |
if(me.next) | |
me.next->prev = &me; | |
waiting.head = &me; | |
while(waiting.muxer && me.msg==nil) | |
rsleep(&me.r); | |
if(!me.msg){ | |
if(waiting.muxer) | |
abort(); | |
waiting.muxer = 1; | |
while(!me.msg){ | |
qunlock(&waiting.lk); | |
msg = recvp(threadwaitchan()); | |
qlock(&waiting.lk); | |
if(msg == nil) /* shouldn't happen */ | |
break; | |
for(w=waiting.head; w; w=w->next) | |
if(w->pid == msg->pid) | |
break; | |
if(w){ | |
if(w->prev) | |
w->prev->next = w->next; | |
else | |
waiting.head = w->next; | |
if(w->next) | |
w->next->prev = w->prev; | |
me.msg = msg; | |
rwakeup(&w->r); | |
}else{ | |
waiting.msg = realloc(waiting.msg, (waiting.nmsg+1)*sizeof waiting.msg[0]); | |
if(waiting.msg == nil) | |
sysfatal("out of memory"); | |
waiting.msg[waiting.nmsg++] = msg; | |
} | |
} | |
waiting.muxer = 0; | |
if(waiting.head) | |
rwakeup(&waiting.head->r); | |
} | |
qunlock(&waiting.lk); | |
if (me.msg->pid < 0) { | |
free(me.msg); | |
me.msg = 0; | |
} | |
return me.msg; | |
} |