aboutsummaryrefslogtreecommitdiff
path: root/libgo/runtime/chan.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2014-06-06 22:37:27 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2014-06-06 22:37:27 +0000
commit6736ef96eab222e58e6294f42be981a5afb59811 (patch)
tree2bc668fae9bf96f9a3988e0b0a16685bde8c4f0b /libgo/runtime/chan.c
parent38a138411da4206c53f9a153ee9c3624fce58a52 (diff)
downloadgcc-6736ef96eab222e58e6294f42be981a5afb59811.zip
gcc-6736ef96eab222e58e6294f42be981a5afb59811.tar.gz
gcc-6736ef96eab222e58e6294f42be981a5afb59811.tar.bz2
libgo: Merge to master revision 19184.
The next revision, 19185, renames several runtime files, and will be handled in a separate change. From-SVN: r211328
Diffstat (limited to 'libgo/runtime/chan.c')
-rw-r--r--libgo/runtime/chan.c334
1 files changed, 144 insertions, 190 deletions
diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c
index 6bd12e4..cd3a2c5 100644
--- a/libgo/runtime/chan.c
+++ b/libgo/runtime/chan.c
@@ -8,8 +8,6 @@
#include "race.h"
#include "malloc.h"
-#define NOSELGEN 1
-
typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG;
typedef struct Select Select;
@@ -20,8 +18,8 @@ typedef struct __go_channel_type ChanType;
struct SudoG
{
- G* g; // g and selgen constitute
- uint32 selgen; // a weak pointer to g
+ G* g;
+ uint32* selectdone;
SudoG* link;
int64 releasetime;
byte* elem; // data element
@@ -43,6 +41,7 @@ struct Hchan
uint8 elemalign;
uint8 pad; // ensures proper alignment of the buffer that follows Hchan in memory
bool closed;
+ const Type* elemtype; // element type
uintgo sendx; // send index
uintgo recvx; // receive index
WaitQ recvq; // list of recv waiters
@@ -89,8 +88,8 @@ static SudoG* dequeue(WaitQ*);
static void enqueue(WaitQ*, SudoG*);
static void racesync(Hchan*, SudoG*);
-Hchan*
-runtime_makechan_c(ChanType *t, int64 hint)
+static Hchan*
+makechan(ChanType *t, int64 hint)
{
Hchan *c;
uintptr n;
@@ -102,16 +101,16 @@ runtime_makechan_c(ChanType *t, int64 hint)
if(elem->__size >= (1<<16))
runtime_throw("makechan: invalid channel element type");
- if(hint < 0 || (intgo)hint != hint || (elem->__size > 0 && (uintptr)hint > MaxMem / elem->__size))
+ if(hint < 0 || (intgo)hint != hint || (elem->__size > 0 && (uintptr)hint > (MaxMem - sizeof(*c)) / elem->__size))
runtime_panicstring("makechan: size out of range");
n = sizeof(*c);
n = ROUND(n, elem->__align);
// allocate memory in one call
- c = (Hchan*)runtime_mallocgc(n + hint*elem->__size, (uintptr)t | TypeInfo_Chan, 0);
+ c = (Hchan*)runtime_mallocgc(sizeof(*c) + hint*elem->__size, (uintptr)t | TypeInfo_Chan, 0);
c->elemsize = elem->__size;
- c->elemalign = elem->__align;
+ c->elemtype = elem;
c->dataqsiz = hint;
if(debug)
@@ -131,7 +130,7 @@ reflect_makechan(ChanType *t, uint64 size)
{
Hchan *c;
- c = runtime_makechan_c(t, size);
+ c = makechan(t, size);
return c;
}
@@ -139,13 +138,13 @@ reflect_makechan(ChanType *t, uint64 size)
Hchan*
__go_new_channel(ChanType *t, uintptr hint)
{
- return runtime_makechan_c(t, hint);
+ return makechan(t, hint);
}
Hchan*
__go_new_channel_big(ChanType *t, uint64 hint)
{
- return runtime_makechan_c(t, hint);
+ return makechan(t, hint);
}
/*
@@ -162,8 +161,8 @@ __go_new_channel_big(ChanType *t, uint64 hint)
* been closed. it is easiest to loop and re-run
* the operation; we'll see that it's now closed.
*/
-void
-runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
+static bool
+chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc)
{
SudoG *sg;
SudoG mysg;
@@ -173,14 +172,15 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
g = runtime_g();
+ if(raceenabled)
+ runtime_racereadobjectpc(ep, t->__element_type, runtime_getcallerpc(&t), chansend);
+
if(c == nil) {
USED(t);
- if(pres != nil) {
- *pres = false;
- return;
- }
+ if(!block)
+ return false;
runtime_park(nil, nil, "chan send (nil chan)");
- return; // not reached
+ return false; // not reached
}
if(runtime_gcwaiting())
@@ -199,7 +199,7 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
runtime_lock(c);
if(raceenabled)
- runtime_racereadpc(c, pc, runtime_chansend);
+ runtime_racereadpc(c, pc, chansend);
if(c->closed)
goto closed;
@@ -219,24 +219,20 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(sg->releasetime)
sg->releasetime = runtime_cputicks();
runtime_ready(gp);
-
- if(pres != nil)
- *pres = true;
- return;
+ return true;
}
- if(pres != nil) {
+ if(!block) {
runtime_unlock(c);
- *pres = false;
- return;
+ return false;
}
mysg.elem = ep;
mysg.g = g;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
g->param = nil;
enqueue(&c->sendq, &mysg);
- runtime_park(runtime_unlock, c, "chan send");
+ runtime_parkunlock(c, "chan send");
if(g->param == nil) {
runtime_lock(c);
@@ -248,23 +244,22 @@ runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
asynch:
if(c->closed)
goto closed;
if(c->qcount >= c->dataqsiz) {
- if(pres != nil) {
+ if(!block) {
runtime_unlock(c);
- *pres = false;
- return;
+ return false;
}
mysg.g = g;
mysg.elem = nil;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
enqueue(&c->sendq, &mysg);
- runtime_park(runtime_unlock, c, "chan send");
+ runtime_parkunlock(c, "chan send");
runtime_lock(c);
goto asynch;
@@ -287,20 +282,19 @@ asynch:
runtime_ready(gp);
} else
runtime_unlock(c);
- if(pres != nil)
- *pres = true;
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
closed:
runtime_unlock(c);
runtime_panicstring("send on closed channel");
+ return false; // not reached
}
-void
-runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
+static bool
+chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received)
{
SudoG *sg;
SudoG mysg;
@@ -311,6 +305,8 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
if(runtime_gcwaiting())
runtime_gosched();
+ // raceenabled: don't need to check ep, as it is always on the stack.
+
if(debug)
runtime_printf("chanrecv: chan=%p\n", c);
@@ -318,12 +314,10 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
if(c == nil) {
USED(t);
- if(selected != nil) {
- *selected = false;
- return;
- }
+ if(!block)
+ return false;
runtime_park(nil, nil, "chan receive (nil chan)");
- return; // not reached
+ return false; // not reached
}
t0 = 0;
@@ -354,25 +348,22 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
sg->releasetime = runtime_cputicks();
runtime_ready(gp);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = true;
- return;
+ return true;
}
- if(selected != nil) {
+ if(!block) {
runtime_unlock(c);
- *selected = false;
- return;
+ return false;
}
mysg.elem = ep;
mysg.g = g;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
g->param = nil;
enqueue(&c->recvq, &mysg);
- runtime_park(runtime_unlock, c, "chan receive");
+ runtime_parkunlock(c, "chan receive");
if(g->param == nil) {
runtime_lock(c);
@@ -385,25 +376,24 @@ runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
*received = true;
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
asynch:
if(c->qcount <= 0) {
if(c->closed)
goto closed;
- if(selected != nil) {
+ if(!block) {
runtime_unlock(c);
- *selected = false;
if(received != nil)
*received = false;
- return;
+ return false;
}
mysg.g = g;
mysg.elem = nil;
- mysg.selgen = NOSELGEN;
+ mysg.selectdone = nil;
enqueue(&c->recvq, &mysg);
- runtime_park(runtime_unlock, c, "chan receive");
+ runtime_parkunlock(c, "chan receive");
runtime_lock(c);
goto asynch;
@@ -429,19 +419,15 @@ asynch:
} else
runtime_unlock(c);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = true;
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
- return;
+ return true;
closed:
if(ep != nil)
runtime_memclr(ep, c->elemsize);
- if(selected != nil)
- *selected = true;
if(received != nil)
*received = false;
if(raceenabled)
@@ -449,6 +435,7 @@ closed:
runtime_unlock(c);
if(mysg.releasetime > 0)
runtime_blockevent(mysg.releasetime - t0, 2);
+ return true;
}
// The compiler generates a call to __go_send_small to send a value 8
@@ -461,46 +448,46 @@ __go_send_small(ChanType *t, Hchan* c, uint64 val)
byte b[sizeof(uint64)];
uint64 v;
} u;
- byte *p;
+ byte *v;
u.v = val;
#ifndef WORDS_BIGENDIAN
- p = u.b;
+ v = u.b;
#else
- p = u.b + sizeof(uint64) - t->__element_type->__size;
+ v = u.b + sizeof(uint64) - t->__element_type->__size;
#endif
- runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
+ chansend(t, c, v, true, runtime_getcallerpc(&t));
}
// The compiler generates a call to __go_send_big to send a value
// larger than 8 bytes or smaller.
void
-__go_send_big(ChanType *t, Hchan* c, byte* p)
+__go_send_big(ChanType *t, Hchan* c, byte* v)
{
- runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
+ chansend(t, c, v, true, runtime_getcallerpc(&t));
}
// The compiler generates a call to __go_receive to receive a
// value from a channel.
void
-__go_receive(ChanType *t, Hchan* c, byte* p)
+__go_receive(ChanType *t, Hchan* c, byte* v)
{
- runtime_chanrecv(t, c, p, nil, nil);
+ chanrecv(t, c, v, true, nil);
}
-_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
+_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* v)
__asm__ (GOSYM_PREFIX "runtime.chanrecv2");
_Bool
-runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
+runtime_chanrecv2(ChanType *t, Hchan* c, byte* v)
{
bool received;
- runtime_chanrecv(t, c, p, nil, &received);
+ chanrecv(t, c, v, true, &received);
return received;
}
-// func selectnbsend(c chan any, elem any) bool
+// func selectnbsend(c chan any, elem *any) bool
//
// compiler implements
//
@@ -520,12 +507,12 @@ runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
// }
//
_Bool
-runtime_selectnbsend(ChanType *t, Hchan *c, byte *p)
+runtime_selectnbsend(ChanType *t, Hchan *c, byte *val)
{
bool res;
- runtime_chansend(t, c, p, &res, runtime_getcallerpc(&t));
- return res;
+ res = chansend(t, c, val, false, runtime_getcallerpc(&t));
+ return (_Bool)res;
}
// func selectnbrecv(elem *any, c chan any) bool
@@ -552,8 +539,8 @@ runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c)
{
bool selected;
- runtime_chanrecv(t, c, v, &selected, nil);
- return selected;
+ selected = chanrecv(t, c, v, false, nil);
+ return (_Bool)selected;
}
// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
@@ -582,88 +569,60 @@ runtime_selectnbrecv2(ChanType *t, byte *v, _Bool *received, Hchan *c)
bool r;
r = false;
- runtime_chanrecv(t, c, v, &selected, received == nil ? nil : &r);
+ selected = chanrecv(t, c, v, false, received == nil ? nil : &r);
if(received != nil)
*received = r;
return selected;
}
// For reflect:
-// func chansend(c chan, val iword, nb bool) (selected bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+// func chansend(c chan, val *any, nb bool) (selected bool)
+// where val points to the data to be sent.
+//
+// The "uintptr selected" is really "bool selected" but saying
+// uintptr gets us the right alignment for the output parameter block.
-_Bool reflect_chansend(ChanType *, Hchan *, uintptr, _Bool)
+_Bool reflect_chansend(ChanType *, Hchan *, byte *, _Bool)
__asm__ (GOSYM_PREFIX "reflect.chansend");
_Bool
-reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb)
+reflect_chansend(ChanType *t, Hchan *c, byte *val, _Bool nb)
{
bool selected;
- bool *sp;
- byte *vp;
- if(nb) {
- selected = false;
- sp = (bool*)&selected;
- } else {
- selected = true;
- sp = nil;
- }
- if(__go_is_pointer_type(t->__element_type))
- vp = (byte*)&val;
- else
- vp = (byte*)val;
- runtime_chansend(t, c, vp, sp, runtime_getcallerpc(&t));
- return selected;
+ selected = chansend(t, c, val, !nb, runtime_getcallerpc(&t));
+ return (_Bool)selected;
}
// For reflect:
-// func chanrecv(c chan, nb bool) (val iword, selected, received bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+// func chanrecv(c chan, nb bool, val *any) (selected, received bool)
+// where val points to a data area that will be filled in with the
+// received value. val must have the size and type of the channel element type.
struct chanrecv_ret
{
- uintptr val;
_Bool selected;
_Bool received;
};
-struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool)
+struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool, byte *val)
__asm__ (GOSYM_PREFIX "reflect.chanrecv");
struct chanrecv_ret
-reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb)
+reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb, byte *val)
{
struct chanrecv_ret ret;
- byte *vp;
- bool *sp;
bool selected;
bool received;
- if(nb) {
- selected = false;
- sp = &selected;
- } else {
- ret.selected = true;
- sp = nil;
- }
received = false;
- if(__go_is_pointer_type(t->__element_type)) {
- vp = (byte*)&ret.val;
- } else {
- vp = runtime_mal(t->__element_type->__size);
- ret.val = (uintptr)vp;
- }
- runtime_chanrecv(t, c, vp, sp, &received);
- if(nb)
- ret.selected = selected;
- ret.received = received;
+ selected = chanrecv(t, c, val, !nb, &received);
+ ret.selected = (_Bool)selected;
+ ret.received = (_Bool)received;
return ret;
}
-static void newselect(int32, Select**);
+static Select* newselect(int32);
// newselect(size uint32) (sel *byte);
@@ -672,14 +631,11 @@ void* runtime_newselect(int32) __asm__ (GOSYM_PREFIX "runtime.newselect");
void*
runtime_newselect(int32 size)
{
- Select *sel;
-
- newselect(size, &sel);
- return (void*)sel;
+ return (void*)newselect(size);
}
-static void
-newselect(int32 size, Select **selp)
+static Select*
+newselect(int32 size)
{
int32 n;
Select *sel;
@@ -701,10 +657,10 @@ newselect(int32 size, Select **selp)
sel->ncase = 0;
sel->lockorder = (void*)(sel->scase + size);
sel->pollorder = (void*)(sel->lockorder + size);
- *selp = sel;
if(debug)
runtime_printf("newselect s=%p size=%d\n", sel, size);
+ return sel;
}
// cut in half to give stack a chance to split
@@ -880,6 +836,14 @@ selunlock(Select *sel)
}
}
+static bool
+selparkcommit(G *gp, void *sel)
+{
+ USED(gp);
+ selunlock(sel);
+ return true;
+}
+
void
runtime_block(void)
{
@@ -902,7 +866,7 @@ static int
selectgo(Select **selp)
{
Select *sel;
- uint32 o, i, j, k;
+ uint32 o, i, j, k, done;
int64 t0;
Scase *cas, *dfl;
Hchan *c;
@@ -1008,7 +972,7 @@ loop:
case CaseSend:
if(raceenabled)
- runtime_racereadpc(c, runtime_selectgo, runtime_chansend);
+ runtime_racereadpc(c, runtime_selectgo, chansend);
if(c->closed)
goto sclose;
if(c->dataqsiz > 0) {
@@ -1035,13 +999,14 @@ loop:
// pass 2 - enqueue on all chans
+ done = 0;
for(i=0; i<sel->ncase; i++) {
o = sel->pollorder[i];
cas = &sel->scase[o];
c = cas->chan;
sg = &cas->sg;
sg->g = g;
- sg->selgen = g->selgen;
+ sg->selectdone = &done;
switch(cas->kind) {
case CaseRecv:
@@ -1055,7 +1020,7 @@ loop:
}
g->param = nil;
- runtime_park((void(*)(Lock*))selunlock, (Lock*)sel, "select");
+ runtime_park(selparkcommit, sel, "select");
sellock(sel);
sg = g->param;
@@ -1091,13 +1056,23 @@ loop:
*cas->receivedp = true;
}
+ if(raceenabled) {
+ if(cas->kind == CaseRecv && cas->sg.elem != nil)
+ runtime_racewriteobjectpc(cas->sg.elem, c->elemtype, selectgo, chanrecv);
+ else if(cas->kind == CaseSend)
+ runtime_racereadobjectpc(cas->sg.elem, c->elemtype, selectgo, chansend);
+ }
+
selunlock(sel);
goto retc;
asyncrecv:
// can receive from buffer
- if(raceenabled)
+ if(raceenabled) {
+ if(cas->sg.elem != nil)
+ runtime_racewriteobjectpc(cas->sg.elem, c->elemtype, selectgo, chanrecv);
runtime_raceacquire(chanbuf(c, c->recvx));
+ }
if(cas->receivedp != nil)
*cas->receivedp = true;
if(cas->sg.elem != nil)
@@ -1120,8 +1095,10 @@ asyncrecv:
asyncsend:
// can send to buffer
- if(raceenabled)
+ if(raceenabled) {
runtime_racerelease(chanbuf(c, c->sendx));
+ runtime_racereadobjectpc(cas->sg.elem, c->elemtype, selectgo, chansend);
+ }
runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize);
if(++c->sendx == c->dataqsiz)
c->sendx = 0;
@@ -1140,8 +1117,11 @@ asyncsend:
syncrecv:
// can receive from sleeping sender (sg)
- if(raceenabled)
+ if(raceenabled) {
+ if(cas->sg.elem != nil)
+ runtime_racewriteobjectpc(cas->sg.elem, c->elemtype, selectgo, chanrecv);
racesync(c, sg);
+ }
selunlock(sel);
if(debug)
runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
@@ -1169,8 +1149,10 @@ rclose:
syncsend:
// can send to sleeping receiver (sg)
- if(raceenabled)
+ if(raceenabled) {
+ runtime_racereadobjectpc(cas->sg.elem, c->elemtype, selectgo, chansend);
racesync(c, sg);
+ }
selunlock(sel);
if(debug)
runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
@@ -1204,7 +1186,7 @@ struct runtimeSelect
uintptr dir;
ChanType *typ;
Hchan *ch;
- uintptr val;
+ byte *val;
};
// This enum must match ../reflect/value.go:/SelectDir.
@@ -1214,14 +1196,13 @@ enum SelectDir {
SelectDefault,
};
+// func rselect(cases []runtimeSelect) (chosen int, recvOK bool)
+
struct rselect_ret {
intgo chosen;
- uintptr word;
- bool recvOK;
+ _Bool recvOK;
};
-// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
-
struct rselect_ret reflect_rselect(Slice)
__asm__ (GOSYM_PREFIX "reflect.rselect");
@@ -1229,36 +1210,18 @@ struct rselect_ret
reflect_rselect(Slice cases)
{
struct rselect_ret ret;
+ intgo chosen;
+ bool recvOK;
int32 i;
Select *sel;
runtimeSelect* rcase, *rc;
- void *elem;
- void *recvptr;
- uintptr maxsize;
- bool onlyptr;
- ret.chosen = -1;
- ret.word = 0;
- ret.recvOK = false;
+ chosen = -1;
+ recvOK = false;
- maxsize = 0;
- onlyptr = true;
rcase = (runtimeSelect*)cases.__values;
- for(i=0; i<cases.__count; i++) {
- rc = &rcase[i];
- if(rc->dir == SelectRecv && rc->ch != nil) {
- if(maxsize < rc->typ->__element_type->__size)
- maxsize = rc->typ->__element_type->__size;
- if(!__go_is_pointer_type(rc->typ->__element_type))
- onlyptr = false;
- }
- }
-
- recvptr = nil;
- if(!onlyptr)
- recvptr = runtime_mal(maxsize);
- newselect(cases.__count, &sel);
+ sel = newselect(cases.__count);
for(i=0; i<cases.__count; i++) {
rc = &rcase[i];
switch(rc->dir) {
@@ -1268,28 +1231,20 @@ reflect_rselect(Slice cases)
case SelectSend:
if(rc->ch == nil)
break;
- if(!__go_is_pointer_type(rc->typ->__element_type))
- elem = (void*)rc->val;
- else
- elem = (void*)&rc->val;
- selectsend(sel, rc->ch, i, elem);
+ selectsend(sel, rc->ch, i, rc->val);
break;
case SelectRecv:
if(rc->ch == nil)
break;
- if(!__go_is_pointer_type(rc->typ->__element_type))
- elem = recvptr;
- else
- elem = &ret.word;
- selectrecv(sel, rc->ch, i, elem, &ret.recvOK);
+ selectrecv(sel, rc->ch, i, rc->val, &recvOK);
break;
}
}
- ret.chosen = (intgo)(uintptr)selectgo(&sel);
- if(rcase[ret.chosen].dir == SelectRecv && !__go_is_pointer_type(rcase[ret.chosen].typ->__element_type))
- ret.word = (uintptr)recvptr;
+ chosen = (intgo)(uintptr)selectgo(&sel);
+ ret.chosen = chosen;
+ ret.recvOK = (_Bool)recvOK;
return ret;
}
@@ -1428,12 +1383,11 @@ loop:
return nil;
q->first = sgp->link;
- // if sgp is stale, ignore it
- if(sgp->selgen != NOSELGEN &&
- (sgp->selgen != sgp->g->selgen ||
- !runtime_cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
- //prints("INVALID PSEUDOG POINTER\n");
- goto loop;
+ // if sgp participates in a select and is already signaled, ignore it
+ if(sgp->selectdone != nil) {
+ // claim the right to signal
+ if(*sgp->selectdone != 0 || !runtime_cas(sgp->selectdone, 0, 1))
+ goto loop;
}
return sgp;