1
0
mirror of https://github.com/golang/go synced 2024-10-02 10:18:33 -06:00
go/src/runtime/chan.c

222 lines
4.1 KiB
C
Raw Normal View History

2008-07-13 15:29:46 -06:00
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
2008-07-14 15:33:39 -06:00
static int32 debug = 0;
2008-07-13 15:29:46 -06:00
typedef struct Hchan Hchan;
2008-07-14 15:33:39 -06:00
typedef struct Link Link;
2008-07-13 15:29:46 -06:00
struct Hchan
{
uint32 elemsize;
2008-07-14 15:33:39 -06:00
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
uint32 eo; // vararg of element
uint32 po; // vararg of present bool
Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender
Link* recvdataq; // pointer for receiver
WaitQ recvq; // list of recv waiters
WaitQ sendq; // list of send waiters
};
struct Link
{
Link* link;
2008-07-14 18:41:38 -06:00
byte elem[8];
2008-07-13 15:29:46 -06:00
};
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
void
sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
Hchan* ret)
{
Hchan *c;
2008-07-14 15:33:39 -06:00
int32 i;
2008-07-13 15:29:46 -06:00
if(elemalg >= nelem(algarray)) {
prints("0<=");
sys·printint(elemalg);
prints("<");
sys·printint(nelem(algarray));
prints("\n");
throw("sys·newchan: elem algorithm out of range");
}
c = mal(sizeof(*c));
c->elemsize = elemsize;
c->elemalg = &algarray[elemalg];
2008-07-14 15:33:39 -06:00
if(hint > 0) {
Link *d, *b, *e;
// make a circular q
b = nil;
e = nil;
for(i=0; i<hint; i++) {
d = mal(sizeof(*d));
if(e == nil)
e = d;
d->link = b;
b = d;
}
e->link = b;
c->recvdataq = b;
c->senddataq = b;
c->qcount = 0;
c->dataqsiz = hint;
}
2008-07-13 15:29:46 -06:00
// these calculations are compiler dependent
c->eo = rnd(sizeof(c), elemsize);
2008-07-14 15:33:39 -06:00
c->po = rnd(c->eo+elemsize, 1);
2008-07-13 15:29:46 -06:00
ret = c;
FLUSH(&ret);
if(debug) {
prints("newchan: chan=");
sys·printpointer(c);
prints("; elemsize=");
sys·printint(elemsize);
prints("; elemalg=");
sys·printint(elemalg);
2008-07-14 15:33:39 -06:00
prints("; dataqsiz=");
sys·printint(c->dataqsiz);
2008-07-13 15:29:46 -06:00
prints("\n");
}
2008-07-14 15:33:39 -06:00
2008-07-13 15:29:46 -06:00
}
// chansend(hchan *chan any, elem any);
void
sys·chansend(Hchan* c, ...)
{
byte *ae;
2008-07-14 15:33:39 -06:00
G *gr;
2008-07-13 15:29:46 -06:00
ae = (byte*)&c + c->eo;
if(debug) {
prints("chansend: chan=");
sys·printpointer(c);
prints("; elem=");
c->elemalg->print(c->elemsize, ae);
prints("\n");
}
2008-07-14 15:33:39 -06:00
if(c->dataqsiz > 0)
goto asynch;
gr = dequeue(&c->recvq);
if(gr != nil) {
c->elemalg->copy(c->elemsize, gr->elem, ae);
gr->status = Grunnable;
return;
}
c->elemalg->copy(c->elemsize, g->elem, ae);
g->status = Gwaiting;
enqueue(&c->sendq, g);
sys·gosched();
return;
asynch:
2008-07-14 18:41:38 -06:00
while(c->qcount >= c->dataqsiz) {
g->status = Gwaiting;
enqueue(&c->sendq, g);
sys·gosched();
}
c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
c->senddataq = c->senddataq->link;
c->qcount++;
gr = dequeue(&c->recvq);
if(gr != nil)
gr->status = Grunnable;
2008-07-13 15:29:46 -06:00
}
2008-07-13 17:20:27 -06:00
// chanrecv1(hchan *chan any) (elem any);
void
sys·chanrecv1(Hchan* c, ...)
{
byte *ae;
2008-07-14 15:33:39 -06:00
G *gs;
2008-07-13 17:20:27 -06:00
ae = (byte*)&c + c->eo;
if(debug) {
prints("chanrecv1: chan=");
sys·printpointer(c);
prints("\n");
}
2008-07-14 15:33:39 -06:00
if(c->dataqsiz > 0)
goto asynch;
gs = dequeue(&c->sendq);
if(gs != nil) {
c->elemalg->copy(c->elemsize, ae, gs->elem);
gs->status = Grunnable;
return;
}
g->status = Gwaiting;
enqueue(&c->recvq, g);
sys·gosched();
c->elemalg->copy(c->elemsize, ae, g->elem);
return;
asynch:
2008-07-14 18:41:38 -06:00
while(c->qcount <= 0) {
g->status = Gwaiting;
enqueue(&c->recvq, g);
sys·gosched();
}
c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
c->qcount--;
gs = dequeue(&c->sendq);
if(gs != nil)
gs->status = Grunnable;
2008-07-13 17:20:27 -06:00
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
void
sys·chanrecv2(Hchan* c, ...)
{
2008-07-14 15:33:39 -06:00
byte *ae, *ap;
2008-07-14 18:41:38 -06:00
G *gs;
2008-07-13 17:20:27 -06:00
ae = (byte*)&c + c->eo;
2008-07-14 15:33:39 -06:00
ap = (byte*)&c + c->po;
2008-07-13 17:20:27 -06:00
if(debug) {
prints("chanrecv2: chan=");
sys·printpointer(c);
prints("\n");
}
2008-07-14 15:33:39 -06:00
if(c->dataqsiz > 0)
goto asynch;
2008-07-14 18:41:38 -06:00
gs = dequeue(&c->sendq);
if(gs != nil) {
c->elemalg->copy(c->elemsize, ae, gs->elem);
gs->status = Grunnable;
*ap = true;
return;
}
*ap = false;
return;
2008-07-14 15:33:39 -06:00
asynch:
2008-07-14 18:41:38 -06:00
if(c->qcount <= 0) {
*ap = false;
return;
}
c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
c->qcount--;
gs = dequeue(&c->sendq);
if(gs != nil)
gs->status = Grunnable;
*ap = true;
2008-07-13 17:20:27 -06:00
}