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