1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 
5 typedef struct Waiter Waiter;
6 
7 struct {
8 	QLock lk;
9 	Waitmsg **msg;
10 	int nmsg;
11 	int muxer;
12 	Waiter *head;
13 } waiting;
14 
15 struct Waiter
16 {
17 	Rendez r;
18 	Waitmsg *msg;
19 	int pid;
20 	Waiter *next;
21 	Waiter *prev;
22 };
23 
24 /* see src/libmux/mux.c */
25 Waitmsg*
procwait(int pid)26 procwait(int pid)
27 {
28 	Waiter *w;
29 	Waiter me;
30 	Waitmsg *msg;
31 	int i;
32 
33 	memset(&me, 0, sizeof me);
34 	me.pid = pid;
35 	me.r.l = &waiting.lk;
36 
37 	qlock(&waiting.lk);
38 	for(i=0; i<waiting.nmsg; i++){
39 		if(waiting.msg[i]->pid == pid){
40 			msg = waiting.msg[i];
41 			waiting.msg[i] = waiting.msg[--waiting.nmsg];
42 			qunlock(&waiting.lk);
43 			return msg;
44 		}
45 	}
46 	me.next = waiting.head;
47 	me.prev = nil;
48 	if(me.next)
49 		me.next->prev = &me;
50 	waiting.head = &me;
51 	while(waiting.muxer && me.msg==nil)
52 		rsleep(&me.r);
53 
54 	if(!me.msg){
55 		if(waiting.muxer)
56 			abort();
57 		waiting.muxer = 1;
58 		while(!me.msg){
59 			qunlock(&waiting.lk);
60 			msg = recvp(threadwaitchan());
61 			qlock(&waiting.lk);
62 			if(msg == nil)	/* shouldn't happen */
63 				break;
64 			for(w=waiting.head; w; w=w->next)
65 				if(w->pid == msg->pid)
66 					break;
67 			if(w){
68 				if(w->prev)
69 					w->prev->next = w->next;
70 				else
71 					waiting.head = w->next;
72 				if(w->next)
73 					w->next->prev = w->prev;
74 				me.msg = msg;
75 				rwakeup(&w->r);
76 			}else{
77 				waiting.msg = realloc(waiting.msg, (waiting.nmsg+1)*sizeof waiting.msg[0]);
78 				if(waiting.msg == nil)
79 					sysfatal("out of memory");
80 				waiting.msg[waiting.nmsg++] = msg;
81 			}
82 		}
83 		waiting.muxer = 0;
84 		if(waiting.head)
85 			rwakeup(&waiting.head->r);
86 	}
87 	qunlock(&waiting.lk);
88 	if (me.msg->pid < 0) {
89 		free(me.msg);
90 		me.msg = 0;
91 	}
92 	return me.msg;
93 }
94