Blame


1 76193d7c 2003-09-30 devnull #include "threadimpl.h"
2 76193d7c 2003-09-30 devnull
3 76193d7c 2003-09-30 devnull static Lock chanlock; /* central channel access lock */
4 76193d7c 2003-09-30 devnull
5 06bb4ed2 2004-09-17 devnull static void enqueue(Alt*, Thread*);
6 76193d7c 2003-09-30 devnull static void dequeue(Alt*);
7 76193d7c 2003-09-30 devnull static int altexec(Alt*, int);
8 76193d7c 2003-09-30 devnull
9 76193d7c 2003-09-30 devnull int _threadhighnentry;
10 76193d7c 2003-09-30 devnull int _threadnalt;
11 76193d7c 2003-09-30 devnull
12 02a1a5c1 2004-03-05 devnull static void
13 02a1a5c1 2004-03-05 devnull setuserpc(ulong pc)
14 02a1a5c1 2004-03-05 devnull {
15 02a1a5c1 2004-03-05 devnull Thread *t;
16 02a1a5c1 2004-03-05 devnull
17 02a1a5c1 2004-03-05 devnull t = _threadgetproc()->thread;
18 02a1a5c1 2004-03-05 devnull if(t)
19 02a1a5c1 2004-03-05 devnull t->userpc = pc;
20 02a1a5c1 2004-03-05 devnull }
21 02a1a5c1 2004-03-05 devnull
22 76193d7c 2003-09-30 devnull static int
23 76193d7c 2003-09-30 devnull canexec(Alt *a)
24 76193d7c 2003-09-30 devnull {
25 76193d7c 2003-09-30 devnull int i, otherop;
26 76193d7c 2003-09-30 devnull Channel *c;
27 76193d7c 2003-09-30 devnull
28 76193d7c 2003-09-30 devnull c = a->c;
29 76193d7c 2003-09-30 devnull /* are there senders or receivers blocked? */
30 76193d7c 2003-09-30 devnull otherop = (CHANSND+CHANRCV) - a->op;
31 76193d7c 2003-09-30 devnull for(i=0; i<c->nentry; i++)
32 bcf527a9 2004-09-17 devnull if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->thread->altc==nil){
33 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "can rendez alt %p chan %p", a, c);
34 76193d7c 2003-09-30 devnull return 1;
35 76193d7c 2003-09-30 devnull }
36 76193d7c 2003-09-30 devnull
37 76193d7c 2003-09-30 devnull /* is there room in the channel? */
38 76193d7c 2003-09-30 devnull if((a->op==CHANSND && c->n < c->s)
39 76193d7c 2003-09-30 devnull || (a->op==CHANRCV && c->n > 0)){
40 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "can buffer alt %p chan %p", a, c);
41 76193d7c 2003-09-30 devnull return 1;
42 76193d7c 2003-09-30 devnull }
43 76193d7c 2003-09-30 devnull
44 76193d7c 2003-09-30 devnull return 0;
45 76193d7c 2003-09-30 devnull }
46 76193d7c 2003-09-30 devnull
47 76193d7c 2003-09-30 devnull static void
48 76193d7c 2003-09-30 devnull _chanfree(Channel *c)
49 76193d7c 2003-09-30 devnull {
50 76193d7c 2003-09-30 devnull int i, inuse;
51 76193d7c 2003-09-30 devnull
52 76193d7c 2003-09-30 devnull inuse = 0;
53 76193d7c 2003-09-30 devnull for(i = 0; i < c->nentry; i++)
54 76193d7c 2003-09-30 devnull if(c->qentry[i])
55 76193d7c 2003-09-30 devnull inuse = 1;
56 76193d7c 2003-09-30 devnull if(inuse)
57 76193d7c 2003-09-30 devnull c->freed = 1;
58 76193d7c 2003-09-30 devnull else{
59 76193d7c 2003-09-30 devnull if(c->qentry)
60 76193d7c 2003-09-30 devnull free(c->qentry);
61 76193d7c 2003-09-30 devnull free(c);
62 76193d7c 2003-09-30 devnull }
63 76193d7c 2003-09-30 devnull }
64 76193d7c 2003-09-30 devnull
65 76193d7c 2003-09-30 devnull void
66 76193d7c 2003-09-30 devnull chanfree(Channel *c)
67 76193d7c 2003-09-30 devnull {
68 76193d7c 2003-09-30 devnull lock(&chanlock);
69 76193d7c 2003-09-30 devnull _chanfree(c);
70 76193d7c 2003-09-30 devnull unlock(&chanlock);
71 76193d7c 2003-09-30 devnull }
72 76193d7c 2003-09-30 devnull
73 76193d7c 2003-09-30 devnull int
74 76193d7c 2003-09-30 devnull chaninit(Channel *c, int elemsize, int elemcnt)
75 76193d7c 2003-09-30 devnull {
76 76193d7c 2003-09-30 devnull if(elemcnt < 0 || elemsize <= 0 || c == nil)
77 76193d7c 2003-09-30 devnull return -1;
78 5a8e63b2 2004-02-29 devnull memset(c, 0, sizeof *c);
79 76193d7c 2003-09-30 devnull c->e = elemsize;
80 76193d7c 2003-09-30 devnull c->s = elemcnt;
81 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "chaninit %p", c);
82 76193d7c 2003-09-30 devnull return 1;
83 76193d7c 2003-09-30 devnull }
84 76193d7c 2003-09-30 devnull
85 76193d7c 2003-09-30 devnull Channel*
86 76193d7c 2003-09-30 devnull chancreate(int elemsize, int elemcnt)
87 76193d7c 2003-09-30 devnull {
88 76193d7c 2003-09-30 devnull Channel *c;
89 76193d7c 2003-09-30 devnull
90 76193d7c 2003-09-30 devnull if(elemcnt < 0 || elemsize <= 0)
91 76193d7c 2003-09-30 devnull return nil;
92 76193d7c 2003-09-30 devnull c = _threadmalloc(sizeof(Channel)+elemsize*elemcnt, 1);
93 76193d7c 2003-09-30 devnull c->e = elemsize;
94 76193d7c 2003-09-30 devnull c->s = elemcnt;
95 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "chancreate %p", c);
96 76193d7c 2003-09-30 devnull return c;
97 76193d7c 2003-09-30 devnull }
98 76193d7c 2003-09-30 devnull
99 02a1a5c1 2004-03-05 devnull static int
100 02a1a5c1 2004-03-05 devnull _alt(Alt *alts)
101 76193d7c 2003-09-30 devnull {
102 76193d7c 2003-09-30 devnull Alt *a, *xa;
103 06bb4ed2 2004-09-17 devnull Channel *c;
104 76193d7c 2003-09-30 devnull int n, s;
105 76193d7c 2003-09-30 devnull Thread *t;
106 76193d7c 2003-09-30 devnull
107 76193d7c 2003-09-30 devnull /*
108 76193d7c 2003-09-30 devnull * The point of going splhi here is that note handlers
109 76193d7c 2003-09-30 devnull * might reasonably want to use channel operations,
110 76193d7c 2003-09-30 devnull * but that will hang if the note comes while we hold the
111 76193d7c 2003-09-30 devnull * chanlock. Instead, we delay the note until we've dropped
112 76193d7c 2003-09-30 devnull * the lock.
113 5a8e63b2 2004-02-29 devnull */
114 5a8e63b2 2004-02-29 devnull
115 5a8e63b2 2004-02-29 devnull /*
116 5a8e63b2 2004-02-29 devnull * T might be nil here -- the scheduler sends on threadwaitchan
117 5a8e63b2 2004-02-29 devnull * directly (in non-blocking mode, of course!).
118 76193d7c 2003-09-30 devnull */
119 76193d7c 2003-09-30 devnull t = _threadgetproc()->thread;
120 5a8e63b2 2004-02-29 devnull if((t && t->moribund) || _threadexitsallstatus)
121 76193d7c 2003-09-30 devnull yield(); /* won't return */
122 76193d7c 2003-09-30 devnull s = _procsplhi();
123 76193d7c 2003-09-30 devnull lock(&chanlock);
124 76193d7c 2003-09-30 devnull
125 76193d7c 2003-09-30 devnull /* test whether any channels can proceed */
126 76193d7c 2003-09-30 devnull n = 0;
127 76193d7c 2003-09-30 devnull a = nil;
128 76193d7c 2003-09-30 devnull
129 76193d7c 2003-09-30 devnull for(xa=alts; xa->op!=CHANEND && xa->op!=CHANNOBLK; xa++){
130 76193d7c 2003-09-30 devnull xa->entryno = -1;
131 76193d7c 2003-09-30 devnull if(xa->op == CHANNOP)
132 76193d7c 2003-09-30 devnull continue;
133 06bb4ed2 2004-09-17 devnull
134 76193d7c 2003-09-30 devnull c = xa->c;
135 76193d7c 2003-09-30 devnull if(c==nil){
136 76193d7c 2003-09-30 devnull unlock(&chanlock);
137 76193d7c 2003-09-30 devnull _procsplx(s);
138 76193d7c 2003-09-30 devnull return -1;
139 76193d7c 2003-09-30 devnull }
140 76193d7c 2003-09-30 devnull if(canexec(xa))
141 76193d7c 2003-09-30 devnull if(nrand(++n) == 0)
142 76193d7c 2003-09-30 devnull a = xa;
143 76193d7c 2003-09-30 devnull }
144 76193d7c 2003-09-30 devnull
145 76193d7c 2003-09-30 devnull if(a==nil){
146 76193d7c 2003-09-30 devnull /* nothing can proceed */
147 76193d7c 2003-09-30 devnull if(xa->op == CHANNOBLK){
148 76193d7c 2003-09-30 devnull unlock(&chanlock);
149 76193d7c 2003-09-30 devnull _procsplx(s);
150 76193d7c 2003-09-30 devnull _threadnalt++;
151 76193d7c 2003-09-30 devnull return xa - alts;
152 76193d7c 2003-09-30 devnull }
153 76193d7c 2003-09-30 devnull
154 76193d7c 2003-09-30 devnull /* enqueue on all channels. */
155 06bb4ed2 2004-09-17 devnull t->altc = nil;
156 76193d7c 2003-09-30 devnull for(xa=alts; xa->op!=CHANEND; xa++){
157 76193d7c 2003-09-30 devnull if(xa->op==CHANNOP)
158 76193d7c 2003-09-30 devnull continue;
159 06bb4ed2 2004-09-17 devnull enqueue(xa, t);
160 76193d7c 2003-09-30 devnull }
161 76193d7c 2003-09-30 devnull
162 76193d7c 2003-09-30 devnull /*
163 76193d7c 2003-09-30 devnull * wait for successful rendezvous.
164 76193d7c 2003-09-30 devnull * we can't just give up if the rendezvous
165 76193d7c 2003-09-30 devnull * is interrupted -- someone else might come
166 76193d7c 2003-09-30 devnull * along and try to rendezvous with us, so
167 76193d7c 2003-09-30 devnull * we need to be here.
168 06bb4ed2 2004-09-17 devnull *
169 06bb4ed2 2004-09-17 devnull * actually, now we're assuming no interrupts.
170 76193d7c 2003-09-30 devnull */
171 06bb4ed2 2004-09-17 devnull /*Again:*/
172 5a8e63b2 2004-02-29 devnull t->alt = alts;
173 5a8e63b2 2004-02-29 devnull t->chan = Chanalt;
174 06bb4ed2 2004-09-17 devnull t->altrend.l = &chanlock;
175 76193d7c 2003-09-30 devnull _procsplx(s);
176 06bb4ed2 2004-09-17 devnull _threadsleep(&t->altrend);
177 76193d7c 2003-09-30 devnull s = _procsplhi();
178 76193d7c 2003-09-30 devnull
179 76193d7c 2003-09-30 devnull /* dequeue from channels, find selected one */
180 76193d7c 2003-09-30 devnull a = nil;
181 06bb4ed2 2004-09-17 devnull c = t->altc;
182 76193d7c 2003-09-30 devnull for(xa=alts; xa->op!=CHANEND; xa++){
183 76193d7c 2003-09-30 devnull if(xa->op==CHANNOP)
184 76193d7c 2003-09-30 devnull continue;
185 76193d7c 2003-09-30 devnull if(xa->c == c)
186 76193d7c 2003-09-30 devnull a = xa;
187 76193d7c 2003-09-30 devnull dequeue(xa);
188 76193d7c 2003-09-30 devnull }
189 76193d7c 2003-09-30 devnull unlock(&chanlock);
190 76193d7c 2003-09-30 devnull _procsplx(s);
191 76193d7c 2003-09-30 devnull if(a == nil){ /* we were interrupted */
192 76193d7c 2003-09-30 devnull assert(c==(Channel*)~0);
193 76193d7c 2003-09-30 devnull return -1;
194 76193d7c 2003-09-30 devnull }
195 76193d7c 2003-09-30 devnull }else{
196 76193d7c 2003-09-30 devnull altexec(a, s); /* unlocks chanlock, does splx */
197 76193d7c 2003-09-30 devnull }
198 8c6f0e8a 2004-03-05 devnull if(t)
199 8c6f0e8a 2004-03-05 devnull t->chan = Channone;
200 76193d7c 2003-09-30 devnull return a - alts;
201 76193d7c 2003-09-30 devnull }
202 76193d7c 2003-09-30 devnull
203 02a1a5c1 2004-03-05 devnull int
204 02a1a5c1 2004-03-05 devnull alt(Alt *alts)
205 02a1a5c1 2004-03-05 devnull {
206 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&alts));
207 02a1a5c1 2004-03-05 devnull return _alt(alts);
208 02a1a5c1 2004-03-05 devnull }
209 02a1a5c1 2004-03-05 devnull
210 76193d7c 2003-09-30 devnull static int
211 76193d7c 2003-09-30 devnull runop(int op, Channel *c, void *v, int nb)
212 76193d7c 2003-09-30 devnull {
213 76193d7c 2003-09-30 devnull int r;
214 76193d7c 2003-09-30 devnull Alt a[2];
215 76193d7c 2003-09-30 devnull
216 76193d7c 2003-09-30 devnull /*
217 76193d7c 2003-09-30 devnull * we could do this without calling alt,
218 76193d7c 2003-09-30 devnull * but the only reason would be performance,
219 76193d7c 2003-09-30 devnull * and i'm not convinced it matters.
220 76193d7c 2003-09-30 devnull */
221 76193d7c 2003-09-30 devnull a[0].op = op;
222 76193d7c 2003-09-30 devnull a[0].c = c;
223 76193d7c 2003-09-30 devnull a[0].v = v;
224 76193d7c 2003-09-30 devnull a[1].op = CHANEND;
225 76193d7c 2003-09-30 devnull if(nb)
226 76193d7c 2003-09-30 devnull a[1].op = CHANNOBLK;
227 02a1a5c1 2004-03-05 devnull switch(r=_alt(a)){
228 76193d7c 2003-09-30 devnull case -1: /* interrupted */
229 76193d7c 2003-09-30 devnull return -1;
230 76193d7c 2003-09-30 devnull case 1: /* nonblocking, didn't accomplish anything */
231 76193d7c 2003-09-30 devnull assert(nb);
232 76193d7c 2003-09-30 devnull return 0;
233 76193d7c 2003-09-30 devnull case 0:
234 76193d7c 2003-09-30 devnull return 1;
235 76193d7c 2003-09-30 devnull default:
236 76193d7c 2003-09-30 devnull fprint(2, "ERROR: channel alt returned %d\n", r);
237 76193d7c 2003-09-30 devnull abort();
238 76193d7c 2003-09-30 devnull return -1;
239 76193d7c 2003-09-30 devnull }
240 76193d7c 2003-09-30 devnull }
241 76193d7c 2003-09-30 devnull
242 76193d7c 2003-09-30 devnull int
243 76193d7c 2003-09-30 devnull recv(Channel *c, void *v)
244 76193d7c 2003-09-30 devnull {
245 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
246 76193d7c 2003-09-30 devnull return runop(CHANRCV, c, v, 0);
247 76193d7c 2003-09-30 devnull }
248 76193d7c 2003-09-30 devnull
249 76193d7c 2003-09-30 devnull int
250 76193d7c 2003-09-30 devnull nbrecv(Channel *c, void *v)
251 76193d7c 2003-09-30 devnull {
252 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
253 76193d7c 2003-09-30 devnull return runop(CHANRCV, c, v, 1);
254 76193d7c 2003-09-30 devnull }
255 76193d7c 2003-09-30 devnull
256 76193d7c 2003-09-30 devnull int
257 76193d7c 2003-09-30 devnull send(Channel *c, void *v)
258 76193d7c 2003-09-30 devnull {
259 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
260 76193d7c 2003-09-30 devnull return runop(CHANSND, c, v, 0);
261 76193d7c 2003-09-30 devnull }
262 76193d7c 2003-09-30 devnull
263 76193d7c 2003-09-30 devnull int
264 76193d7c 2003-09-30 devnull nbsend(Channel *c, void *v)
265 76193d7c 2003-09-30 devnull {
266 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
267 76193d7c 2003-09-30 devnull return runop(CHANSND, c, v, 1);
268 76193d7c 2003-09-30 devnull }
269 76193d7c 2003-09-30 devnull
270 76193d7c 2003-09-30 devnull static void
271 76193d7c 2003-09-30 devnull channelsize(Channel *c, int sz)
272 76193d7c 2003-09-30 devnull {
273 76193d7c 2003-09-30 devnull if(c->e != sz){
274 a3785ca2 2004-04-21 devnull fprint(2, "expected channel with elements of size %d, got size %d\n",
275 76193d7c 2003-09-30 devnull sz, c->e);
276 76193d7c 2003-09-30 devnull abort();
277 76193d7c 2003-09-30 devnull }
278 76193d7c 2003-09-30 devnull }
279 76193d7c 2003-09-30 devnull
280 76193d7c 2003-09-30 devnull int
281 76193d7c 2003-09-30 devnull sendul(Channel *c, ulong v)
282 76193d7c 2003-09-30 devnull {
283 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
284 76193d7c 2003-09-30 devnull channelsize(c, sizeof(ulong));
285 76193d7c 2003-09-30 devnull return send(c, &v);
286 76193d7c 2003-09-30 devnull }
287 76193d7c 2003-09-30 devnull
288 76193d7c 2003-09-30 devnull ulong
289 76193d7c 2003-09-30 devnull recvul(Channel *c)
290 76193d7c 2003-09-30 devnull {
291 76193d7c 2003-09-30 devnull ulong v;
292 76193d7c 2003-09-30 devnull
293 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
294 76193d7c 2003-09-30 devnull channelsize(c, sizeof(ulong));
295 02a1a5c1 2004-03-05 devnull if(runop(CHANRCV, c, &v, 0) < 0)
296 76193d7c 2003-09-30 devnull return ~0;
297 76193d7c 2003-09-30 devnull return v;
298 76193d7c 2003-09-30 devnull }
299 76193d7c 2003-09-30 devnull
300 76193d7c 2003-09-30 devnull int
301 76193d7c 2003-09-30 devnull sendp(Channel *c, void *v)
302 76193d7c 2003-09-30 devnull {
303 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
304 76193d7c 2003-09-30 devnull channelsize(c, sizeof(void*));
305 02a1a5c1 2004-03-05 devnull return runop(CHANSND, c, &v, 0);
306 76193d7c 2003-09-30 devnull }
307 76193d7c 2003-09-30 devnull
308 76193d7c 2003-09-30 devnull void*
309 76193d7c 2003-09-30 devnull recvp(Channel *c)
310 76193d7c 2003-09-30 devnull {
311 76193d7c 2003-09-30 devnull void *v;
312 76193d7c 2003-09-30 devnull
313 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
314 76193d7c 2003-09-30 devnull channelsize(c, sizeof(void*));
315 02a1a5c1 2004-03-05 devnull if(runop(CHANRCV, c, &v, 0) < 0)
316 76193d7c 2003-09-30 devnull return nil;
317 76193d7c 2003-09-30 devnull return v;
318 76193d7c 2003-09-30 devnull }
319 76193d7c 2003-09-30 devnull
320 76193d7c 2003-09-30 devnull int
321 76193d7c 2003-09-30 devnull nbsendul(Channel *c, ulong v)
322 76193d7c 2003-09-30 devnull {
323 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
324 76193d7c 2003-09-30 devnull channelsize(c, sizeof(ulong));
325 02a1a5c1 2004-03-05 devnull return runop(CHANSND, c, &v, 1);
326 76193d7c 2003-09-30 devnull }
327 76193d7c 2003-09-30 devnull
328 76193d7c 2003-09-30 devnull ulong
329 76193d7c 2003-09-30 devnull nbrecvul(Channel *c)
330 76193d7c 2003-09-30 devnull {
331 76193d7c 2003-09-30 devnull ulong v;
332 76193d7c 2003-09-30 devnull
333 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
334 76193d7c 2003-09-30 devnull channelsize(c, sizeof(ulong));
335 02a1a5c1 2004-03-05 devnull if(runop(CHANRCV, c, &v, 1) == 0)
336 76193d7c 2003-09-30 devnull return 0;
337 76193d7c 2003-09-30 devnull return v;
338 76193d7c 2003-09-30 devnull }
339 76193d7c 2003-09-30 devnull
340 76193d7c 2003-09-30 devnull int
341 76193d7c 2003-09-30 devnull nbsendp(Channel *c, void *v)
342 76193d7c 2003-09-30 devnull {
343 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
344 76193d7c 2003-09-30 devnull channelsize(c, sizeof(void*));
345 02a1a5c1 2004-03-05 devnull return runop(CHANSND, c, &v, 1);
346 76193d7c 2003-09-30 devnull }
347 76193d7c 2003-09-30 devnull
348 76193d7c 2003-09-30 devnull void*
349 76193d7c 2003-09-30 devnull nbrecvp(Channel *c)
350 76193d7c 2003-09-30 devnull {
351 76193d7c 2003-09-30 devnull void *v;
352 76193d7c 2003-09-30 devnull
353 02a1a5c1 2004-03-05 devnull setuserpc(getcallerpc(&c));
354 76193d7c 2003-09-30 devnull channelsize(c, sizeof(void*));
355 02a1a5c1 2004-03-05 devnull if(runop(CHANRCV, c, &v, 1) == 0)
356 76193d7c 2003-09-30 devnull return nil;
357 76193d7c 2003-09-30 devnull return v;
358 76193d7c 2003-09-30 devnull }
359 76193d7c 2003-09-30 devnull
360 76193d7c 2003-09-30 devnull static int
361 76193d7c 2003-09-30 devnull emptyentry(Channel *c)
362 76193d7c 2003-09-30 devnull {
363 76193d7c 2003-09-30 devnull int i, extra;
364 76193d7c 2003-09-30 devnull
365 76193d7c 2003-09-30 devnull assert((c->nentry==0 && c->qentry==nil) || (c->nentry && c->qentry));
366 76193d7c 2003-09-30 devnull
367 76193d7c 2003-09-30 devnull for(i=0; i<c->nentry; i++)
368 76193d7c 2003-09-30 devnull if(c->qentry[i]==nil)
369 76193d7c 2003-09-30 devnull return i;
370 76193d7c 2003-09-30 devnull
371 76193d7c 2003-09-30 devnull extra = 16;
372 76193d7c 2003-09-30 devnull c->nentry += extra;
373 76193d7c 2003-09-30 devnull if(c->nentry > _threadhighnentry) _threadhighnentry = c->nentry;
374 76193d7c 2003-09-30 devnull c->qentry = realloc((void*)c->qentry, c->nentry*sizeof(c->qentry[0]));
375 76193d7c 2003-09-30 devnull if(c->qentry == nil)
376 76193d7c 2003-09-30 devnull sysfatal("realloc channel entries: %r");
377 76193d7c 2003-09-30 devnull _threadmemset(&c->qentry[i], 0, extra*sizeof(c->qentry[0]));
378 76193d7c 2003-09-30 devnull return i;
379 76193d7c 2003-09-30 devnull }
380 76193d7c 2003-09-30 devnull
381 76193d7c 2003-09-30 devnull static void
382 06bb4ed2 2004-09-17 devnull enqueue(Alt *a, Thread *t)
383 76193d7c 2003-09-30 devnull {
384 76193d7c 2003-09-30 devnull int i;
385 76193d7c 2003-09-30 devnull
386 912fba95 2003-11-24 devnull _threaddebug(DBGCHAN, "Queueing alt %p on channel %p", a, a->c);
387 06bb4ed2 2004-09-17 devnull a->thread = t;
388 76193d7c 2003-09-30 devnull i = emptyentry(a->c);
389 76193d7c 2003-09-30 devnull a->c->qentry[i] = a;
390 76193d7c 2003-09-30 devnull }
391 76193d7c 2003-09-30 devnull
392 76193d7c 2003-09-30 devnull static void
393 76193d7c 2003-09-30 devnull dequeue(Alt *a)
394 76193d7c 2003-09-30 devnull {
395 76193d7c 2003-09-30 devnull int i;
396 76193d7c 2003-09-30 devnull Channel *c;
397 76193d7c 2003-09-30 devnull
398 76193d7c 2003-09-30 devnull c = a->c;
399 76193d7c 2003-09-30 devnull for(i=0; i<c->nentry; i++)
400 76193d7c 2003-09-30 devnull if(c->qentry[i]==a){
401 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "Dequeuing alt %p from channel %p", a, a->c);
402 76193d7c 2003-09-30 devnull c->qentry[i] = nil;
403 76193d7c 2003-09-30 devnull if(c->freed)
404 76193d7c 2003-09-30 devnull _chanfree(c);
405 76193d7c 2003-09-30 devnull return;
406 76193d7c 2003-09-30 devnull }
407 76193d7c 2003-09-30 devnull }
408 76193d7c 2003-09-30 devnull
409 76193d7c 2003-09-30 devnull static void*
410 76193d7c 2003-09-30 devnull altexecbuffered(Alt *a, int willreplace)
411 76193d7c 2003-09-30 devnull {
412 76193d7c 2003-09-30 devnull uchar *v;
413 76193d7c 2003-09-30 devnull Channel *c;
414 76193d7c 2003-09-30 devnull
415 76193d7c 2003-09-30 devnull c = a->c;
416 76193d7c 2003-09-30 devnull /* use buffered channel queue */
417 76193d7c 2003-09-30 devnull if(a->op==CHANRCV && c->n > 0){
418 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "buffer recv alt %p chan %p", a, c);
419 76193d7c 2003-09-30 devnull v = c->v + c->e*(c->f%c->s);
420 76193d7c 2003-09-30 devnull if(!willreplace)
421 76193d7c 2003-09-30 devnull c->n--;
422 76193d7c 2003-09-30 devnull c->f++;
423 76193d7c 2003-09-30 devnull return v;
424 76193d7c 2003-09-30 devnull }
425 76193d7c 2003-09-30 devnull if(a->op==CHANSND && c->n < c->s){
426 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "buffer send alt %p chan %p", a, c);
427 76193d7c 2003-09-30 devnull v = c->v + c->e*((c->f+c->n)%c->s);
428 76193d7c 2003-09-30 devnull if(!willreplace)
429 76193d7c 2003-09-30 devnull c->n++;
430 76193d7c 2003-09-30 devnull return v;
431 76193d7c 2003-09-30 devnull }
432 76193d7c 2003-09-30 devnull abort();
433 76193d7c 2003-09-30 devnull return nil;
434 76193d7c 2003-09-30 devnull }
435 76193d7c 2003-09-30 devnull
436 76193d7c 2003-09-30 devnull static void
437 76193d7c 2003-09-30 devnull altcopy(void *dst, void *src, int sz)
438 76193d7c 2003-09-30 devnull {
439 76193d7c 2003-09-30 devnull if(dst){
440 76193d7c 2003-09-30 devnull if(src)
441 76193d7c 2003-09-30 devnull memmove(dst, src, sz);
442 76193d7c 2003-09-30 devnull else
443 76193d7c 2003-09-30 devnull _threadmemset(dst, 0, sz);
444 76193d7c 2003-09-30 devnull }
445 76193d7c 2003-09-30 devnull }
446 76193d7c 2003-09-30 devnull
447 76193d7c 2003-09-30 devnull static int
448 76193d7c 2003-09-30 devnull altexec(Alt *a, int spl)
449 76193d7c 2003-09-30 devnull {
450 76193d7c 2003-09-30 devnull volatile Alt *b;
451 76193d7c 2003-09-30 devnull int i, n, otherop;
452 76193d7c 2003-09-30 devnull Channel *c;
453 76193d7c 2003-09-30 devnull void *me, *waiter, *buf;
454 76193d7c 2003-09-30 devnull
455 76193d7c 2003-09-30 devnull c = a->c;
456 76193d7c 2003-09-30 devnull
457 76193d7c 2003-09-30 devnull /* rendezvous with others */
458 76193d7c 2003-09-30 devnull otherop = (CHANSND+CHANRCV) - a->op;
459 76193d7c 2003-09-30 devnull n = 0;
460 76193d7c 2003-09-30 devnull b = nil;
461 76193d7c 2003-09-30 devnull me = a->v;
462 76193d7c 2003-09-30 devnull for(i=0; i<c->nentry; i++)
463 bcf527a9 2004-09-17 devnull if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->thread->altc==nil)
464 76193d7c 2003-09-30 devnull if(nrand(++n) == 0)
465 76193d7c 2003-09-30 devnull b = c->qentry[i];
466 76193d7c 2003-09-30 devnull if(b != nil){
467 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "rendez %s alt %p chan %p alt %p", a->op==CHANRCV?"recv":"send", a, c, b);
468 76193d7c 2003-09-30 devnull waiter = b->v;
469 76193d7c 2003-09-30 devnull if(c->s && c->n){
470 76193d7c 2003-09-30 devnull /*
471 76193d7c 2003-09-30 devnull * if buffer is full and there are waiters
472 76193d7c 2003-09-30 devnull * and we're meeting a waiter,
473 76193d7c 2003-09-30 devnull * we must be receiving.
474 76193d7c 2003-09-30 devnull *
475 76193d7c 2003-09-30 devnull * we use the value in the channel buffer,
476 76193d7c 2003-09-30 devnull * copy the waiter's value into the channel buffer
477 76193d7c 2003-09-30 devnull * on behalf of the waiter, and then wake the waiter.
478 76193d7c 2003-09-30 devnull */
479 76193d7c 2003-09-30 devnull if(a->op!=CHANRCV)
480 76193d7c 2003-09-30 devnull abort();
481 76193d7c 2003-09-30 devnull buf = altexecbuffered(a, 1);
482 76193d7c 2003-09-30 devnull altcopy(me, buf, c->e);
483 76193d7c 2003-09-30 devnull altcopy(buf, waiter, c->e);
484 76193d7c 2003-09-30 devnull }else{
485 76193d7c 2003-09-30 devnull if(a->op==CHANRCV)
486 76193d7c 2003-09-30 devnull altcopy(me, waiter, c->e);
487 76193d7c 2003-09-30 devnull else
488 76193d7c 2003-09-30 devnull altcopy(waiter, me, c->e);
489 76193d7c 2003-09-30 devnull }
490 06bb4ed2 2004-09-17 devnull b->thread->altc = c;
491 bcf527a9 2004-09-17 devnull _threadwakeup(&b->thread->altrend);
492 06bb4ed2 2004-09-17 devnull _threaddebug(DBGCHAN, "chanlock is %lud", *(ulong*)(void*)&chanlock);
493 76193d7c 2003-09-30 devnull _threaddebug(DBGCHAN, "unlocking the chanlock");
494 76193d7c 2003-09-30 devnull unlock(&chanlock);
495 76193d7c 2003-09-30 devnull _procsplx(spl);
496 76193d7c 2003-09-30 devnull return 1;
497 76193d7c 2003-09-30 devnull }
498 76193d7c 2003-09-30 devnull
499 76193d7c 2003-09-30 devnull buf = altexecbuffered(a, 0);
500 76193d7c 2003-09-30 devnull if(a->op==CHANRCV)
501 76193d7c 2003-09-30 devnull altcopy(me, buf, c->e);
502 76193d7c 2003-09-30 devnull else
503 76193d7c 2003-09-30 devnull altcopy(buf, me, c->e);
504 76193d7c 2003-09-30 devnull
505 76193d7c 2003-09-30 devnull unlock(&chanlock);
506 76193d7c 2003-09-30 devnull _procsplx(spl);
507 76193d7c 2003-09-30 devnull return 1;
508 76193d7c 2003-09-30 devnull }