mirror of
https://github.com/golang/go
synced 2024-11-21 20:44:39 -07:00
gc: implement nil chan support
The spec has defined nil chans this way for months. I'm behind. R=ken2 CC=golang-dev https://golang.org/cl/4897050
This commit is contained in:
parent
65bde087ae
commit
3770b0e60c
@ -66,15 +66,14 @@ char *runtimeimport =
|
||||
"func \"\".mapiternext (hiter *any)\n"
|
||||
"func \"\".mapiter1 (hiter *any) any\n"
|
||||
"func \"\".mapiter2 (hiter *any) (key any, val any)\n"
|
||||
"func \"\".makechan (elem *uint8, hint int64) chan any\n"
|
||||
"func \"\".chanrecv1 (hchan <-chan any) any\n"
|
||||
"func \"\".chanrecv2 (hchan <-chan any) (elem any, received bool)\n"
|
||||
"func \"\".chansend1 (hchan chan<- any, elem any)\n"
|
||||
"func \"\".makechan (chanType *uint8, hint int64) chan any\n"
|
||||
"func \"\".chanrecv1 (chanType *uint8, hchan <-chan any) any\n"
|
||||
"func \"\".chanrecv2 (chanType *uint8, hchan <-chan any) (elem any, received bool)\n"
|
||||
"func \"\".chansend1 (chanType *uint8, hchan chan<- any, elem any)\n"
|
||||
"func \"\".closechan (hchan any)\n"
|
||||
"func \"\".closedchan (hchan any) bool\n"
|
||||
"func \"\".selectnbsend (hchan chan<- any, elem any) bool\n"
|
||||
"func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
|
||||
"func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n"
|
||||
"func \"\".selectnbsend (chanType *uint8, hchan chan<- any, elem any) bool\n"
|
||||
"func \"\".selectnbrecv (chanType *uint8, elem *any, hchan <-chan any) bool\n"
|
||||
"func \"\".selectnbrecv2 (chanType *uint8, elem *any, received *bool, hchan <-chan any) bool\n"
|
||||
"func \"\".newselect (size int) *uint8\n"
|
||||
"func \"\".selectsend (sel *uint8, hchan chan<- any, elem *any) bool\n"
|
||||
"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
|
||||
|
@ -91,16 +91,15 @@ func mapiter1(hiter *any) (key any)
|
||||
func mapiter2(hiter *any) (key any, val any)
|
||||
|
||||
// *byte is really *runtime.Type
|
||||
func makechan(elem *byte, hint int64) (hchan chan any)
|
||||
func chanrecv1(hchan <-chan any) (elem any)
|
||||
func chanrecv2(hchan <-chan any) (elem any, received bool)
|
||||
func chansend1(hchan chan<- any, elem any)
|
||||
func makechan(chanType *byte, hint int64) (hchan chan any)
|
||||
func chanrecv1(chanType *byte, hchan <-chan any) (elem any)
|
||||
func chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool)
|
||||
func chansend1(chanType *byte, hchan chan<- any, elem any)
|
||||
func closechan(hchan any)
|
||||
func closedchan(hchan any) bool
|
||||
|
||||
func selectnbsend(hchan chan<- any, elem any) bool
|
||||
func selectnbrecv(elem *any, hchan <-chan any) bool
|
||||
func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
|
||||
func selectnbsend(chanType *byte, hchan chan<- any, elem any) bool
|
||||
func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
|
||||
func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
|
||||
|
||||
func newselect(size int) (sel *byte)
|
||||
func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
|
||||
|
@ -250,9 +250,8 @@ walkselect(Node *sel)
|
||||
case OSEND:
|
||||
// if c != nil && selectnbsend(c, v) { body } else { default body }
|
||||
ch = cheapexpr(n->left, &r->ninit);
|
||||
r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
|
||||
mkcall1(chanfn("selectnbsend", 2, ch->type),
|
||||
types[TBOOL], &r->ninit, ch, n->right));
|
||||
r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type),
|
||||
types[TBOOL], &r->ninit, typename(ch->type), ch, n->right);
|
||||
break;
|
||||
|
||||
case OSELRECV:
|
||||
@ -260,9 +259,8 @@ walkselect(Node *sel)
|
||||
r = nod(OIF, N, N);
|
||||
r->ninit = cas->ninit;
|
||||
ch = cheapexpr(n->right->left, &r->ninit);
|
||||
r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
|
||||
mkcall1(chanfn("selectnbrecv", 2, ch->type),
|
||||
types[TBOOL], &r->ninit, n->left, ch));
|
||||
r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
|
||||
types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
|
||||
break;
|
||||
|
||||
case OSELRECV2:
|
||||
@ -270,9 +268,8 @@ walkselect(Node *sel)
|
||||
r = nod(OIF, N, N);
|
||||
r->ninit = cas->ninit;
|
||||
ch = cheapexpr(n->right->left, &r->ninit);
|
||||
r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
|
||||
mkcall1(chanfn("selectnbrecv2", 2, ch->type),
|
||||
types[TBOOL], &r->ninit, n->left, n->ntest, ch));
|
||||
r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type),
|
||||
types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch);
|
||||
break;
|
||||
}
|
||||
typecheck(&r->ntest, Erv);
|
||||
|
@ -591,7 +591,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
walkexprlistsafe(n->list, init);
|
||||
walkexpr(&r->left, init);
|
||||
fn = chanfn("chanrecv2", 2, r->left->type);
|
||||
r = mkcall1(fn, getoutargx(fn->type), init, r->left);
|
||||
r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left);
|
||||
n->rlist->n = r;
|
||||
n->op = OAS2FUNC;
|
||||
goto as2func;
|
||||
@ -858,7 +858,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
case ORECV:
|
||||
walkexpr(&n->left, init);
|
||||
walkexpr(&n->right, init);
|
||||
n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left);
|
||||
n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, typename(n->left->type), n->left);
|
||||
goto ret;
|
||||
|
||||
case OSLICE:
|
||||
@ -1078,7 +1078,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
|
||||
case OMAKECHAN:
|
||||
n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
|
||||
typename(n->type->type),
|
||||
typename(n->type),
|
||||
conv(n->left, types[TINT64]));
|
||||
goto ret;
|
||||
|
||||
@ -1163,7 +1163,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
goto ret;
|
||||
|
||||
case OSEND:
|
||||
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
|
||||
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n->right);
|
||||
goto ret;
|
||||
|
||||
case OCLOSURE:
|
||||
|
@ -1162,7 +1162,7 @@ func (iv internalValue) recv(nb bool) (val Value, ok bool) {
|
||||
if ch == 0 {
|
||||
panic("recv on nil channel")
|
||||
}
|
||||
valWord, selected, ok := chanrecv(ch, nb)
|
||||
valWord, selected, ok := chanrecv(iv.typ.runtimeType(), ch, nb)
|
||||
if selected {
|
||||
val = valueFromIword(0, t.Elem(), valWord)
|
||||
}
|
||||
@ -1192,7 +1192,7 @@ func (iv internalValue) send(x Value, nb bool) (selected bool) {
|
||||
if ch == 0 {
|
||||
panic("send on nil channel")
|
||||
}
|
||||
return chansend(ch, ix.word, nb)
|
||||
return chansend(iv.typ.runtimeType(), ch, ix.word, nb)
|
||||
}
|
||||
|
||||
// Set assigns x to the value v.
|
||||
@ -1720,8 +1720,8 @@ func convertForAssignment(what string, addr unsafe.Pointer, dst Type, iv interna
|
||||
func chancap(ch iword) int32
|
||||
func chanclose(ch iword)
|
||||
func chanlen(ch iword) int32
|
||||
func chanrecv(ch iword, nb bool) (val iword, selected, received bool)
|
||||
func chansend(ch iword, val iword, nb bool) bool
|
||||
func chanrecv(t *runtime.Type, ch iword, nb bool) (val iword, selected, received bool)
|
||||
func chansend(t *runtime.Type, ch iword, val iword, nb bool) bool
|
||||
|
||||
func makechan(typ *runtime.Type, size uint32) (ch iword)
|
||||
func makemap(t *runtime.Type) iword
|
||||
|
@ -81,10 +81,13 @@ static void enqueue(WaitQ*, SudoG*);
|
||||
static void destroychan(Hchan*);
|
||||
|
||||
Hchan*
|
||||
runtime·makechan_c(Type *elem, int64 hint)
|
||||
runtime·makechan_c(ChanType *t, int64 hint)
|
||||
{
|
||||
Hchan *c;
|
||||
int32 n;
|
||||
Type *elem;
|
||||
|
||||
elem = t->elem;
|
||||
|
||||
if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintptr)-1) / elem->size))
|
||||
runtime·panicstring("makechan: size out of range");
|
||||
@ -121,7 +124,7 @@ runtime·makechan_c(Type *elem, int64 hint)
|
||||
void
|
||||
reflect·makechan(ChanType *t, uint32 size, Hchan *c)
|
||||
{
|
||||
c = runtime·makechan_c(t->elem, size);
|
||||
c = runtime·makechan_c(t, size);
|
||||
FLUSH(&c);
|
||||
}
|
||||
|
||||
@ -132,11 +135,11 @@ destroychan(Hchan *c)
|
||||
}
|
||||
|
||||
|
||||
// makechan(elem *Type, hint int64) (hchan *chan any);
|
||||
// makechan(t *ChanType, hint int64) (hchan *chan any);
|
||||
void
|
||||
runtime·makechan(Type *elem, int64 hint, Hchan *ret)
|
||||
runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
|
||||
{
|
||||
ret = runtime·makechan_c(elem, hint);
|
||||
ret = runtime·makechan_c(t, hint);
|
||||
FLUSH(&ret);
|
||||
}
|
||||
|
||||
@ -155,14 +158,22 @@ runtime·makechan(Type *elem, int64 hint, Hchan *ret)
|
||||
* the operation; we'll see that it's now closed.
|
||||
*/
|
||||
void
|
||||
runtime·chansend(Hchan *c, byte *ep, bool *pres)
|
||||
runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres)
|
||||
{
|
||||
SudoG *sg;
|
||||
SudoG mysg;
|
||||
G* gp;
|
||||
|
||||
if(c == nil)
|
||||
runtime·panicstring("send to nil channel");
|
||||
if(c == nil) {
|
||||
USED(t);
|
||||
if(pres != nil) {
|
||||
*pres = false;
|
||||
return;
|
||||
}
|
||||
g->status = Gwaiting;
|
||||
runtime·gosched();
|
||||
return; // not reached
|
||||
}
|
||||
|
||||
if(runtime·gcwaiting)
|
||||
runtime·gosched();
|
||||
@ -263,21 +274,29 @@ closed:
|
||||
|
||||
|
||||
void
|
||||
runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received)
|
||||
runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
|
||||
{
|
||||
SudoG *sg;
|
||||
SudoG mysg;
|
||||
G *gp;
|
||||
|
||||
if(c == nil)
|
||||
runtime·panicstring("receive from nil channel");
|
||||
|
||||
if(runtime·gcwaiting)
|
||||
runtime·gosched();
|
||||
|
||||
if(debug)
|
||||
runtime·printf("chanrecv: chan=%p\n", c);
|
||||
|
||||
if(c == nil) {
|
||||
USED(t);
|
||||
if(selected != nil) {
|
||||
*selected = false;
|
||||
return;
|
||||
}
|
||||
g->status = Gwaiting;
|
||||
runtime·gosched();
|
||||
return; // not reached
|
||||
}
|
||||
|
||||
runtime·lock(c);
|
||||
if(c->dataqsiz > 0)
|
||||
goto asynch;
|
||||
@ -385,50 +404,29 @@ closed:
|
||||
// chansend1(hchan *chan any, elem any);
|
||||
#pragma textflag 7
|
||||
void
|
||||
runtime·chansend1(Hchan* c, ...)
|
||||
runtime·chansend1(ChanType *t, Hchan* c, ...)
|
||||
{
|
||||
int32 o;
|
||||
byte *ae;
|
||||
|
||||
if(c == nil)
|
||||
runtime·panicstring("send to nil channel");
|
||||
|
||||
o = runtime·rnd(sizeof(c), c->elemalign);
|
||||
ae = (byte*)&c + o;
|
||||
runtime·chansend(c, ae, nil);
|
||||
runtime·chansend(t, c, (byte*)(&c+1), nil);
|
||||
}
|
||||
|
||||
// chanrecv1(hchan *chan any) (elem any);
|
||||
#pragma textflag 7
|
||||
void
|
||||
runtime·chanrecv1(Hchan* c, ...)
|
||||
runtime·chanrecv1(ChanType *t, Hchan* c, ...)
|
||||
{
|
||||
int32 o;
|
||||
byte *ae;
|
||||
|
||||
o = runtime·rnd(sizeof(c), Structrnd);
|
||||
ae = (byte*)&c + o;
|
||||
|
||||
runtime·chanrecv(c, ae, nil, nil);
|
||||
runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil);
|
||||
}
|
||||
|
||||
// chanrecv2(hchan *chan any) (elem any, received bool);
|
||||
#pragma textflag 7
|
||||
void
|
||||
runtime·chanrecv2(Hchan* c, ...)
|
||||
runtime·chanrecv2(ChanType *t, Hchan* c, ...)
|
||||
{
|
||||
int32 o;
|
||||
byte *ae, *ac;
|
||||
|
||||
if(c == nil)
|
||||
runtime·panicstring("receive from nil channel");
|
||||
byte *ae, *ap;
|
||||
|
||||
o = runtime·rnd(sizeof(c), Structrnd);
|
||||
ae = (byte*)&c + o;
|
||||
o += c->elemsize;
|
||||
ac = (byte*)&c + o;
|
||||
|
||||
runtime·chanrecv(c, ae, nil, ac);
|
||||
ae = (byte*)(&c+1);
|
||||
ap = ae + t->elem->size;
|
||||
runtime·chanrecv(t, c, ae, nil, ap);
|
||||
}
|
||||
|
||||
// func selectnbsend(c chan any, elem any) bool
|
||||
@ -444,7 +442,7 @@ runtime·chanrecv2(Hchan* c, ...)
|
||||
//
|
||||
// as
|
||||
//
|
||||
// if c != nil && selectnbsend(c, v) {
|
||||
// if selectnbsend(c, v) {
|
||||
// ... foo
|
||||
// } else {
|
||||
// ... bar
|
||||
@ -452,17 +450,13 @@ runtime·chanrecv2(Hchan* c, ...)
|
||||
//
|
||||
#pragma textflag 7
|
||||
void
|
||||
runtime·selectnbsend(Hchan *c, ...)
|
||||
runtime·selectnbsend(ChanType *t, Hchan *c, ...)
|
||||
{
|
||||
int32 o;
|
||||
byte *ae, *ap;
|
||||
|
||||
o = runtime·rnd(sizeof(c), c->elemalign);
|
||||
ae = (byte*)&c + o;
|
||||
o = runtime·rnd(o+c->elemsize, Structrnd);
|
||||
ap = (byte*)&c + o;
|
||||
|
||||
runtime·chansend(c, ae, ap);
|
||||
ae = (byte*)(&c + 1);
|
||||
ap = ae + runtime·rnd(t->elem->size, Structrnd);
|
||||
runtime·chansend(t, c, ae, ap);
|
||||
}
|
||||
|
||||
// func selectnbrecv(elem *any, c chan any) bool
|
||||
@ -478,7 +472,7 @@ runtime·selectnbsend(Hchan *c, ...)
|
||||
//
|
||||
// as
|
||||
//
|
||||
// if c != nil && selectnbrecv(&v, c) {
|
||||
// if selectnbrecv(&v, c) {
|
||||
// ... foo
|
||||
// } else {
|
||||
// ... bar
|
||||
@ -486,9 +480,9 @@ runtime·selectnbsend(Hchan *c, ...)
|
||||
//
|
||||
#pragma textflag 7
|
||||
void
|
||||
runtime·selectnbrecv(byte *v, Hchan *c, bool selected)
|
||||
runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
|
||||
{
|
||||
runtime·chanrecv(c, v, &selected, nil);
|
||||
runtime·chanrecv(t, c, v, &selected, nil);
|
||||
}
|
||||
|
||||
// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
|
||||
@ -512,9 +506,9 @@ runtime·selectnbrecv(byte *v, Hchan *c, bool selected)
|
||||
//
|
||||
#pragma textflag 7
|
||||
void
|
||||
runtime·selectnbrecv2(byte *v, bool *received, Hchan *c, bool selected)
|
||||
runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected)
|
||||
{
|
||||
runtime·chanrecv(c, v, &selected, received);
|
||||
runtime·chanrecv(t, c, v, &selected, received);
|
||||
}
|
||||
|
||||
// For reflect:
|
||||
@ -525,14 +519,11 @@ runtime·selectnbrecv2(byte *v, bool *received, Hchan *c, bool selected)
|
||||
// The "uintptr selected" is really "bool selected" but saying
|
||||
// uintptr gets us the right alignment for the output parameter block.
|
||||
void
|
||||
reflect·chansend(Hchan *c, uintptr val, bool nb, uintptr selected)
|
||||
reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected)
|
||||
{
|
||||
bool *sp;
|
||||
byte *vp;
|
||||
|
||||
if(c == nil)
|
||||
runtime·panicstring("send to nil channel");
|
||||
|
||||
if(nb) {
|
||||
selected = false;
|
||||
sp = (bool*)&selected;
|
||||
@ -541,11 +532,11 @@ reflect·chansend(Hchan *c, uintptr val, bool nb, uintptr selected)
|
||||
FLUSH(&selected);
|
||||
sp = nil;
|
||||
}
|
||||
if(c->elemsize <= sizeof(val))
|
||||
if(t->elem->size <= sizeof(val))
|
||||
vp = (byte*)&val;
|
||||
else
|
||||
vp = (byte*)val;
|
||||
runtime·chansend(c, vp, sp);
|
||||
runtime·chansend(t, c, vp, sp);
|
||||
}
|
||||
|
||||
// For reflect:
|
||||
@ -553,13 +544,10 @@ reflect·chansend(Hchan *c, uintptr val, bool nb, uintptr selected)
|
||||
// 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.
|
||||
void
|
||||
reflect·chanrecv(Hchan *c, bool nb, uintptr val, bool selected, bool received)
|
||||
reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received)
|
||||
{
|
||||
byte *vp;
|
||||
bool *sp;
|
||||
|
||||
if(c == nil)
|
||||
runtime·panicstring("receive from nil channel");
|
||||
|
||||
if(nb) {
|
||||
selected = false;
|
||||
@ -571,15 +559,15 @@ reflect·chanrecv(Hchan *c, bool nb, uintptr val, bool selected, bool received)
|
||||
}
|
||||
received = false;
|
||||
FLUSH(&received);
|
||||
if(c->elemsize <= sizeof(val)) {
|
||||
if(t->elem->size <= sizeof(val)) {
|
||||
val = 0;
|
||||
vp = (byte*)&val;
|
||||
} else {
|
||||
vp = runtime·mal(c->elemsize);
|
||||
vp = runtime·mal(t->elem->size);
|
||||
val = (uintptr)vp;
|
||||
FLUSH(&val);
|
||||
}
|
||||
runtime·chanrecv(c, vp, sp, &received);
|
||||
runtime·chanrecv(t, c, vp, sp, &received);
|
||||
}
|
||||
|
||||
static void newselect(int32, Select**);
|
||||
|
@ -62,6 +62,7 @@ typedef struct Iface Iface;
|
||||
typedef struct Itab Itab;
|
||||
typedef struct Eface Eface;
|
||||
typedef struct Type Type;
|
||||
typedef struct ChanType ChanType;
|
||||
typedef struct MapType MapType;
|
||||
typedef struct Defer Defer;
|
||||
typedef struct Panic Panic;
|
||||
@ -624,9 +625,9 @@ bool runtime·mapiterkey(struct hash_iter*, void*);
|
||||
void runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
|
||||
Hmap* runtime·makemap_c(MapType*, int64);
|
||||
|
||||
Hchan* runtime·makechan_c(Type*, int64);
|
||||
void runtime·chansend(Hchan*, void*, bool*);
|
||||
void runtime·chanrecv(Hchan*, void*, bool*, bool*);
|
||||
Hchan* runtime·makechan_c(ChanType*, int64);
|
||||
void runtime·chansend(ChanType*, Hchan*, void*, bool*);
|
||||
void runtime·chanrecv(ChanType*, Hchan*, void*, bool*, bool*);
|
||||
int32 runtime·chanlen(Hchan*);
|
||||
int32 runtime·chancap(Hchan*);
|
||||
|
||||
|
@ -16,7 +16,6 @@ typedef struct UncommonType UncommonType;
|
||||
typedef struct InterfaceType InterfaceType;
|
||||
typedef struct Method Method;
|
||||
typedef struct IMethod IMethod;
|
||||
typedef struct ChanType ChanType;
|
||||
typedef struct SliceType SliceType;
|
||||
typedef struct FuncType FuncType;
|
||||
|
||||
|
@ -58,15 +58,15 @@ func main() {
|
||||
closedch := make(chan int)
|
||||
close(closedch)
|
||||
|
||||
// sending/receiving from a nil channel outside a select panics
|
||||
testPanic(always, func() {
|
||||
// sending/receiving from a nil channel blocks
|
||||
testBlock(always, func() {
|
||||
nilch <- 7
|
||||
})
|
||||
testPanic(always, func() {
|
||||
testBlock(always, func() {
|
||||
<-nilch
|
||||
})
|
||||
|
||||
// sending/receiving from a nil channel inside a select never panics
|
||||
// sending/receiving from a nil channel inside a select is never selected
|
||||
testPanic(never, func() {
|
||||
select {
|
||||
case nilch <- 7:
|
||||
|
Loading…
Reference in New Issue
Block a user