]> Cypherpunks repositories - gostls13.git/commitdiff
gc, runtime: make range on channel safe for multiple goroutines
authorRuss Cox <rsc@golang.org>
Tue, 18 Jan 2011 20:59:19 +0000 (15:59 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 18 Jan 2011 20:59:19 +0000 (15:59 -0500)
Fixes #397.

R=ken2
CC=golang-dev
https://golang.org/cl/3994043

src/cmd/gc/builtin.c.boot
src/cmd/gc/go.h
src/cmd/gc/range.c
src/cmd/gc/runtime.go
src/cmd/gc/walk.c
src/pkg/runtime/chan.c
src/pkg/runtime/reflect.goc
src/pkg/runtime/runtime.h

index 380abc64235cd0d02bf89eca6d8fa90129848bc6..af16870fe0ba81a2d85b98e021fcabc5267ba73f 100644 (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"
index 73ea5b9767468bf0267c4e05557a107055e020ef..ee31a335756f3e43c1f289bdb93b6373d30578bf 100644 (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,
index dca3a54542c204da3241ef451b19cdfffdd239b8..4ee8f39a7752d3db7883a1ef21001e6e98ec0a6c 100644 (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);
-
-               n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N);
-               n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N)));
+               hb = nod(OXXX, N, N);
+               tempname(hb, types[TBOOL]);
+
+               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;
 
index 174bc050e5e24a4fa8b4eabca57284c52343a809..59a1171ed0d0f00ab0b5d6b9aa57b7645272dfc1 100644 (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)
index 5faf630b888a58c9d6a7880748ae8b6357739d9a..1d4c5a58e39388b45c40a067bafad99ac5b891ac 100644 (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);
index 94ea513e7af2f066d245dc97e82f87af110e433b..fad437d37962371ad069af68604dc16cb481f0d8 100644 (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);
index a2e3c6ee143ad98971acccb90898ab8cb4ce324e..71d648266edf367c1659bf394fb3b16775bfecf7 100644 (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) {
index 7ba7932b2b843570ef9b2a0b2a2b9f26c6d384e1..3fba06f6172c29f413e1437d998ea0a0dd3952f4 100644 (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*);