1 #include "threadimpl.h"
4 * One can go through a lot of effort to avoid this global lock.
5 * You have to put locks in all the channels and all the Alt
6 * structures. At the beginning of an alt you have to lock all
7 * the channels, but then to try to actually exec an op you
8 * have to lock the other guy's alt structure, so that other
9 * people aren't trying to use him in some other op at the
12 * For Plan 9 apps, it's just not worth the extra effort.
14 static QLock chanlock;
17 chancreate(int elemsize, int bufsize)
21 c = malloc(sizeof *c+bufsize*elemsize);
23 sysfatal("chancreate malloc: %r");
24 memset(c, 0, sizeof *c);
25 c->elemsize = elemsize;
28 c->buf = (uchar*)(c+1);
33 chansetname(Channel *c, char *fmt, ...)
39 name = vsmprint(fmt, arg);
45 /* bug - work out races */
58 addarray(_Altarray *a, Alt *alt)
62 a->a = realloc(a->a, a->m*sizeof a->a[0]);
68 delarray(_Altarray *a, int i)
75 * doesn't really work for things other than CHANSND and CHANRCV
76 * but is only used as arg to chanarray, which can handle it
78 #define otherop(op) (CHANSND+CHANRCV-(op))
81 chanarray(Channel *c, uint op)
99 if(a->op == CHANNOP || (c=a->c) == nil)
102 ar = chanarray(c, otherop(a->op));
109 return c->nbuf < c->bufsize;
123 ar = chanarray(a->c, a->op);
133 ar = chanarray(a->c, a->op);
135 fprint(2, "bad use of altdequeue op=%d\n", a->op);
139 for(i=0; i<ar->n; i++)
144 fprint(2, "cannot find self in altdq\n");
149 altalldequeue(Alt *a)
153 for(i=0; a[i].op!=CHANEND && a[i].op!=CHANNOBLK; i++)
154 if(a[i].op != CHANNOP)
159 amove(void *dst, void *src, uint n)
165 memmove(dst, src, n);
170 * Actually move the data around. There are up to three
171 * players: the sender, the receiver, and the channel itself.
172 * If the channel is unbuffered or the buffer is empty,
173 * data goes from sender to receiver. If the channel is full,
174 * the receiver removes some from the channel and the sender
175 * gets to put some in.
178 altcopy(Alt *s, Alt *r)
185 * Work out who is sender and who is receiver
187 if(s == nil && r == nil)
191 if(s->op == CHANRCV){
196 assert(s==nil || s->op == CHANSND);
197 assert(r==nil || r->op == CHANRCV);
200 * Channel is empty (or unbuffered) - copy directly.
202 if(s && r && c->nbuf == 0){
203 amove(r->v, s->v, c->elemsize);
208 * Otherwise it's always okay to receive and then send.
211 cp = c->buf + c->off*c->elemsize;
212 amove(r->v, cp, c->elemsize);
214 if(++c->off == c->bufsize)
218 cp = c->buf + (c->off+c->nbuf)%c->bufsize*c->elemsize;
219 amove(cp, s->v, c->elemsize);
233 ar = chanarray(c, otherop(a->op));
238 altalldequeue(other->thread->alt);
239 other->thread->alt = other;
240 _threadready(other->thread);
249 int i, j, ncan, n, canblock;
254 for(i=0; a[i].op != CHANEND && a[i].op != CHANNOBLK; i++)
257 canblock = a[i].op == CHANEND;
264 if(dbgalt) print("alt ");
268 if(dbgalt) print(" %c:", "esrnb"[a[i].op]);
269 if(dbgalt) if(c->name) print("%s", c->name); else print("%p", c);
270 if(altcanexec(&a[i])){
271 if(dbgalt) print("*");
278 if(altcanexec(&a[i])){
282 print(" => %c:", "esrnb"[a[i].op]);
283 if(c->name) print("%s", c->name); else print("%p", c);
293 if(dbgalt)print("\n");
301 if(a[i].op != CHANNOP)
309 * the guy who ran the op took care of dequeueing us
310 * and then set t->alt to the one that was executed.
312 if(t->alt < a || t->alt >= a+n)
313 sysfatal("channel bad alt");
318 _chanop(Channel *c, int op, void *p, int canblock)
325 a[1].op = canblock ? CHANEND : CHANNOBLK;
332 chansend(Channel *c, void *v)
334 return _chanop(c, CHANSND, v, 1);
338 channbsend(Channel *c, void *v)
340 return _chanop(c, CHANSND, v, 0);
344 chanrecv(Channel *c, void *v)
346 return _chanop(c, CHANRCV, v, 1);
350 channbrecv(Channel *c, void *v)
352 return _chanop(c, CHANRCV, v, 0);
356 chansendp(Channel *c, void *v)
358 return _chanop(c, CHANSND, (void*)&v, 1);
362 chanrecvp(Channel *c)
366 if(_chanop(c, CHANRCV, (void*)&v, 1) > 0)
372 channbsendp(Channel *c, void *v)
374 return _chanop(c, CHANSND, (void*)&v, 0);
378 channbrecvp(Channel *c)
382 if(_chanop(c, CHANRCV, (void*)&v, 0) > 0)
388 chansendul(Channel *c, ulong val)
390 return _chanop(c, CHANSND, &val, 1);
394 chanrecvul(Channel *c)
398 if(_chanop(c, CHANRCV, &val, 1) > 0)
404 channbsendul(Channel *c, ulong val)
406 return _chanop(c, CHANSND, &val, 0);
410 channbrecvul(Channel *c)
414 if(_chanop(c, CHANRCV, &val, 0) > 0)