blob: 24538e586da3569638eac9b38833edd65ba05fea [file] [log] [blame]
#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;
}