1
0
mirror of https://github.com/golang/go synced 2024-11-24 23:07:56 -07:00

gc, runtime: make range on channel safe for multiple goroutines

Fixes #397.

R=ken2
CC=golang-dev
https://golang.org/cl/3994043
This commit is contained in:
Russ Cox 2011-01-18 15:59:19 -05:00
parent 3426b80dd9
commit b0543ddd8a
8 changed files with 52 additions and 8 deletions

View File

@ -67,6 +67,7 @@ char *runtimeimport =
"func \"\".makechan (elem *uint8, hint int64) chan any\n"
"func \"\".chanrecv1 (hchan <-chan any) any\n"
"func \"\".chanrecv2 (hchan <-chan any) (elem any, pres bool)\n"
"func \"\".chanrecv3 (hchan <-chan any) (elem any, closed bool)\n"
"func \"\".chansend1 (hchan chan<- any, elem any)\n"
"func \"\".chansend2 (hchan chan<- any, elem any) bool\n"
"func \"\".closechan (hchan any)\n"

View File

@ -356,7 +356,7 @@ enum
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2RECVCLOSED, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP,

View File

@ -93,6 +93,7 @@ walkrange(Node *n)
Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
Node *ha, *hit; // hidden aggregate, iterator
Node *hn, *hp; // hidden len, pointer
Node *hb; // hidden bool
Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
Node *fn, *tmp;
NodeList *body, *init;
@ -199,9 +200,15 @@ walkrange(Node *n)
case TCHAN:
hv1 = nod(OXXX, N, n);
tempname(hv1, t->type);
hb = nod(OXXX, N, N);
tempname(hb, types[TBOOL]);
n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N);
n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N)));
n->ntest = nod(ONOT, hb, N);
a = nod(OAS2RECVCLOSED, N, N);
a->typecheck = 1;
a->list = list(list1(hv1), hb);
a->rlist = list1(nod(ORECV, ha, N));
n->ntest->ninit = list1(a);
body = list1(nod(OAS, v1, hv1));
break;

View File

@ -93,6 +93,7 @@ func mapiter2(hiter *any) (key any, val any)
func makechan(elem *byte, hint int64) (hchan chan any)
func chanrecv1(hchan <-chan any) (elem any)
func chanrecv2(hchan <-chan any) (elem any, pres bool)
func chanrecv3(hchan <-chan any) (elem any, closed bool)
func chansend1(hchan chan<- any, elem any)
func chansend2(hchan chan<- any, elem any) (pres bool)
func closechan(hchan any)

View File

@ -404,6 +404,7 @@ walkstmt(Node **np)
case OAS2:
case OAS2DOTTYPE:
case OAS2RECV:
case OAS2RECVCLOSED:
case OAS2FUNC:
case OAS2MAPW:
case OAS2MAPR:
@ -835,6 +836,19 @@ walkexpr(Node **np, NodeList **init)
n->op = OAS2FUNC;
goto as2func;
case OAS2RECVCLOSED:
// a = <-c; b = closed(c) but atomic
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
fn = chanfn("chanrecv3", 2, r->left->type);
r = mkcall1(fn, getoutargx(fn->type), init, r->left);
n->rlist->n = r;
n->op = OAS2FUNC;
goto as2func;
case OAS2MAPR:
// a,b = m[i];
*init = concat(*init, n->ninit);

View File

@ -284,7 +284,7 @@ closed:
}
void
runtime·chanrecv(Hchan* c, byte *ep, bool* pres)
runtime·chanrecv(Hchan* c, byte *ep, bool *pres, bool *closed)
{
SudoG *sg;
G *gp;
@ -299,6 +299,9 @@ runtime·chanrecv(Hchan* c, byte *ep, bool* pres)
runtime·printf("chanrecv: chan=%p\n", c);
runtime·lock(c);
if(closed != nil)
*closed = false;
loop:
if(c->dataqsiz > 0)
goto asynch;
@ -387,6 +390,8 @@ asynch:
return;
closed:
if(closed != nil)
*closed = true;
c->elemalg->copy(c->elemsize, ep, nil);
c->closed |= Rclosed;
incerr(c);
@ -441,7 +446,7 @@ runtime·chanrecv1(Hchan* c, ...)
o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o;
runtime·chanrecv(c, ae, nil);
runtime·chanrecv(c, ae, nil, nil);
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
@ -457,7 +462,23 @@ runtime·chanrecv2(Hchan* c, ...)
o = runtime·rnd(o+c->elemsize, 1);
ap = (byte*)&c + o;
runtime·chanrecv(c, ae, ap);
runtime·chanrecv(c, ae, ap, nil);
}
// chanrecv3(hchan *chan any) (elem any, closed bool);
#pragma textflag 7
void
runtime·chanrecv3(Hchan* c, ...)
{
int32 o;
byte *ae, *ac;
o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o;
o = runtime·rnd(o+c->elemsize, 1);
ac = (byte*)&c + o;
runtime·chanrecv(c, ae, nil, ac);
}
// newselect(size uint32) (sel *byte);

View File

@ -75,7 +75,7 @@ func chansend(ch *byte, val *byte, pres *bool) {
}
func chanrecv(ch *byte, val *byte, pres *bool) {
runtime·chanrecv((Hchan*)ch, val, pres);
runtime·chanrecv((Hchan*)ch, val, pres, nil);
}
func chanclose(ch *byte) {

View File

@ -581,7 +581,7 @@ Hmap* runtime·makemap_c(Type*, Type*, int64);
Hchan* runtime·makechan_c(Type*, int64);
void runtime·chansend(Hchan*, void*, bool*);
void runtime·chanrecv(Hchan*, void*, bool*);
void runtime·chanrecv(Hchan*, void*, bool*, bool*);
void runtime·chanclose(Hchan*);
bool runtime·chanclosed(Hchan*);
int32 runtime·chanlen(Hchan*);