mirror of
https://github.com/golang/go
synced 2024-11-24 22:00:09 -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:
parent
3426b80dd9
commit
b0543ddd8a
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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*);
|
||||
|
Loading…
Reference in New Issue
Block a user