1
0
mirror of https://github.com/golang/go synced 2024-11-22 01:44:40 -07:00

gc, runtime: replace closed(c) with x, ok := <-c

R=ken2, ken3
CC=golang-dev
https://golang.org/cl/4259064
This commit is contained in:
Russ Cox 2011-03-11 14:47:26 -05:00
parent 9f2cb86fe2
commit 8bf34e3356
15 changed files with 259 additions and 148 deletions

View File

@ -66,15 +66,17 @@ char *runtimeimport =
"func \"\".mapiter2 (hiter *any) (key any, val any)\n" "func \"\".mapiter2 (hiter *any) (key any, val any)\n"
"func \"\".makechan (elem *uint8, hint int64) chan any\n" "func \"\".makechan (elem *uint8, hint int64) chan any\n"
"func \"\".chanrecv1 (hchan <-chan any) any\n" "func \"\".chanrecv1 (hchan <-chan any) any\n"
"func \"\".chanrecv3 (hchan <-chan any) (elem any, closed bool)\n" "func \"\".chanrecv2 (hchan <-chan any) (elem any, received bool)\n"
"func \"\".chansend1 (hchan chan<- any, elem any)\n" "func \"\".chansend1 (hchan chan<- any, elem any)\n"
"func \"\".closechan (hchan any)\n" "func \"\".closechan (hchan any)\n"
"func \"\".closedchan (hchan any) bool\n" "func \"\".closedchan (hchan any) bool\n"
"func \"\".selectnbsend (hchan chan<- any, elem any) bool\n" "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n"
"func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n" "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
"func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n"
"func \"\".newselect (size int) *uint8\n" "func \"\".newselect (size int) *uint8\n"
"func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n" "func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n"
"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n" "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
"func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
"func \"\".selectdefault (sel *uint8) bool\n" "func \"\".selectdefault (sel *uint8) bool\n"
"func \"\".selectgo (sel *uint8)\n" "func \"\".selectgo (sel *uint8)\n"
"func \"\".block ()\n" "func \"\".block ()\n"

View File

@ -356,12 +356,11 @@ enum
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR, OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE, OSTRARRAYBYTE, OSTRARRAYRUNE,
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECVCLOSED, OAS2MAPR, OAS2DOTTYPE, OASOP, OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD, OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP, OCAP,
OCLOSE, OCLOSE,
OCLOSED,
OCLOSURE, OCLOSURE,
OCMPIFACE, OCMPSTR, OCMPIFACE, OCMPSTR,
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
@ -389,6 +388,7 @@ enum
ORECV, ORECV,
ORUNESTR, ORUNESTR,
OSELRECV, OSELRECV,
OSELRECV2,
OIOTA, OIOTA,
OREAL, OIMAG, OCOMPLEX, OREAL, OIMAG, OCOMPLEX,

View File

@ -461,23 +461,32 @@ case:
} }
break; break;
} }
| LCASE expr '=' expr ':' | LCASE expr_or_type_list '=' expr ':'
{ {
Node *n;
// will be converted to OCASE // will be converted to OCASE
// right will point to next case // right will point to next case
// done in casebody() // done in casebody()
poptodcl(); poptodcl();
$$ = nod(OXCASE, N, N); $$ = nod(OXCASE, N, N);
$$->list = list1(nod(OAS, $2, $4)); if($2->next == nil)
n = nod(OAS, $2->n, $4);
else {
n = nod(OAS2, N, N);
n->list = $2;
n->rlist = list1($4);
}
$$->list = list1(n);
} }
| LCASE name LCOLAS expr ':' | LCASE expr_or_type_list LCOLAS expr ':'
{ {
// will be converted to OCASE // will be converted to OCASE
// right will point to next case // right will point to next case
// done in casebody() // done in casebody()
poptodcl(); poptodcl();
$$ = nod(OXCASE, N, N); $$ = nod(OXCASE, N, N);
$$->list = list1(colas(list1($2), list1($4))); $$->list = list1(colas($2, list1($4)));
} }
| LDEFAULT ':' | LDEFAULT ':'
{ {

View File

@ -1555,7 +1555,6 @@ static struct
"append", LNAME, Txxx, OAPPEND, "append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP, "cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE, "close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED,
"complex", LNAME, Txxx, OCOMPLEX, "complex", LNAME, Txxx, OCOMPLEX,
"copy", LNAME, Txxx, OCOPY, "copy", LNAME, Txxx, OCOPY,
"imag", LNAME, Txxx, OIMAG, "imag", LNAME, Txxx, OIMAG,

View File

@ -52,7 +52,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OARRAYBYTESTR: case OARRAYBYTESTR:
case OCAP: case OCAP:
case OCLOSE: case OCLOSE:
case OCLOSED:
case OCOPY: case OCOPY:
case OLEN: case OLEN:
case OMAKE: case OMAKE:
@ -405,7 +404,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OAPPEND: case OAPPEND:
case OCAP: case OCAP:
case OCLOSE: case OCLOSE:
case OCLOSED:
case OLEN: case OLEN:
case OCOPY: case OCOPY:
case OMAKE: case OMAKE:

View File

@ -203,8 +203,8 @@ walkrange(Node *n)
hb = nod(OXXX, N, N); hb = nod(OXXX, N, N);
tempname(hb, types[TBOOL]); tempname(hb, types[TBOOL]);
n->ntest = nod(ONOT, hb, N); n->ntest = hb;
a = nod(OAS2RECVCLOSED, N, N); a = nod(OAS2RECV, N, N);
a->typecheck = 1; a->typecheck = 1;
a->list = list(list1(hv1), hb); a->list = list(list1(hv1), hb);
a->rlist = list1(nod(ORECV, ha, N)); a->rlist = list1(nod(ORECV, ha, N));

View File

@ -92,17 +92,19 @@ func mapiter2(hiter *any) (key any, val any)
// *byte is really *runtime.Type // *byte is really *runtime.Type
func makechan(elem *byte, hint int64) (hchan chan any) func makechan(elem *byte, hint int64) (hchan chan any)
func chanrecv1(hchan <-chan any) (elem any) func chanrecv1(hchan <-chan any) (elem any)
func chanrecv3(hchan <-chan any) (elem any, closed bool) func chanrecv2(hchan <-chan any) (elem any, received bool)
func chansend1(hchan chan<- any, elem any) func chansend1(hchan chan<- any, elem any)
func closechan(hchan any) func closechan(hchan any)
func closedchan(hchan any) bool func closedchan(hchan any) bool
func selectnbsend(hchan chan<- any, elem any) bool func selectnbsend(hchan chan<- any, elem any) bool
func selectnbrecv(elem *any, hchan <-chan any) bool func selectnbrecv(elem *any, hchan <-chan any) bool
func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
func newselect(size int) (sel *byte) func newselect(size int) (sel *byte)
func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool) func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool)
func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool) func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
func selectdefault(sel *byte) (selected bool) func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte) func selectgo(sel *byte)
func block() func block()

View File

@ -58,6 +58,18 @@ typecheckselect(Node *sel)
n->op = OSELRECV; n->op = OSELRECV;
break; break;
case OAS2RECV:
// convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok
if(n->right->op != ORECV) {
yyerror("select assignment must have receive on right hand side");
break;
}
n->op = OSELRECV2;
n->left = n->list->n;
n->ntest = n->list->next->n;
n->right = n->rlist->n;
break;
case ORECV: case ORECV:
// convert <-c into OSELRECV(N, <-c) // convert <-c into OSELRECV(N, <-c)
n = nod(OSELRECV, N, n); n = nod(OSELRECV, N, n);
@ -122,6 +134,18 @@ walkselect(Node *sel)
typecheck(&n, Etop); typecheck(&n, Etop);
} }
break; break;
case OSELRECV2:
r = n->right;
ch = cheapexpr(r->left, &l);
r->left = ch;
a = nod(OAS2, N, N);
a->list = n->list;
a->rlist = n->rlist;
n = a;
typecheck(&n, Etop);
break;
} }
// if ch == nil { block() }; n; // if ch == nil { block() }; n;
@ -146,6 +170,7 @@ walkselect(Node *sel)
continue; continue;
switch(n->op) { switch(n->op) {
case OSELRECV: case OSELRECV:
case OSELRECV2:
ch = n->right->left; ch = n->right->left;
// If we can use the address of the target without // If we can use the address of the target without
@ -154,6 +179,28 @@ walkselect(Node *sel)
// Also introduce a temporary for := variables that escape, // Also introduce a temporary for := variables that escape,
// so that we can delay the heap allocation until the case // so that we can delay the heap allocation until the case
// is selected. // is selected.
if(n->op == OSELRECV2) {
if(n->ntest == N || isblank(n->ntest))
n->ntest = nodnil();
else if(n->ntest->op == ONAME &&
(!n->colas || (n->ntest->class&PHEAP) == 0) &&
convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) {
n->ntest = nod(OADDR, n->ntest, N);
n->ntest->etype = 1; // pointer does not escape
typecheck(&n->ntest, Erv);
} else {
tmp = nod(OXXX, N, N);
tempname(tmp, types[TBOOL]);
a = nod(OADDR, tmp, N);
a->etype = 1; // pointer does not escape
typecheck(&a, Erv);
r = nod(OAS, n->ntest, tmp);
typecheck(&r, Etop);
cas->nbody = concat(list1(r), cas->nbody);
n->ntest = a;
}
}
if(n->left == N || isblank(n->left)) if(n->left == N || isblank(n->left))
n->left = nodnil(); n->left = nodnil();
else if(n->left->op == ONAME && else if(n->left->op == ONAME &&
@ -171,10 +218,12 @@ walkselect(Node *sel)
r = nod(OAS, n->left, tmp); r = nod(OAS, n->left, tmp);
typecheck(&r, Etop); typecheck(&r, Etop);
cas->nbody = concat(list1(r), cas->nbody); cas->nbody = concat(list1(r), cas->nbody);
cas->nbody = concat(n->ninit, cas->nbody);
n->ninit = nil;
n->left = a; n->left = a;
} }
cas->nbody = concat(n->ninit, cas->nbody);
n->ninit = nil;
break;
} }
} }
@ -212,6 +261,16 @@ walkselect(Node *sel)
mkcall1(chanfn("selectnbrecv", 2, ch->type), mkcall1(chanfn("selectnbrecv", 2, ch->type),
types[TBOOL], &r->ninit, n->left, ch)); types[TBOOL], &r->ninit, n->left, ch));
break; break;
case OSELRECV2:
// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
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));
break;
} }
typecheck(&r->ntest, Erv); typecheck(&r->ntest, Erv);
r->nbody = cas->nbody; r->nbody = cas->nbody;
@ -254,11 +313,18 @@ walkselect(Node *sel)
r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
&init, var, n->left, n->right); &init, var, n->left, n->right);
break; break;
case OSELRECV: case OSELRECV:
// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL], r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
&init, var, n->right->left, n->left); &init, var, n->right->left, n->left);
break; break;
case OSELRECV2:
// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
&init, var, n->right->left, n->left, n->ntest);
break;
} }
} }
r->nbody = concat(r->nbody, cas->nbody); r->nbody = concat(r->nbody, cas->nbody);

View File

@ -94,7 +94,7 @@ init1(Node *n, NodeList **out)
case OAS2FUNC: case OAS2FUNC:
case OAS2MAPR: case OAS2MAPR:
case OAS2DOTTYPE: case OAS2DOTTYPE:
case OAS2RECVCLOSED: case OAS2RECV:
if(n->defn->initorder) if(n->defn->initorder)
break; break;
n->defn->initorder = 1; n->defn->initorder = 1;

View File

@ -834,7 +834,6 @@ goopnames[] =
[OCALL] = "function call", [OCALL] = "function call",
[OCAP] = "cap", [OCAP] = "cap",
[OCASE] = "case", [OCASE] = "case",
[OCLOSED] = "closed",
[OCLOSE] = "close", [OCLOSE] = "close",
[OCOMPLEX] = "complex", [OCOMPLEX] = "complex",
[OCOM] = "^", [OCOM] = "^",
@ -1669,6 +1668,9 @@ isselect(Node *n)
if(s == n->sym) if(s == n->sym)
return 1; return 1;
s = pkglookup("selectrecv", runtimepkg); s = pkglookup("selectrecv", runtimepkg);
if(s == n->sym)
return 1;
s = pkglookup("selectrecv2", runtimepkg);
if(s == n->sym) if(s == n->sym)
return 1; return 1;
s = pkglookup("selectdefault", runtimepkg); s = pkglookup("selectdefault", runtimepkg);

View File

@ -921,7 +921,6 @@ reswitch:
n->type = t; n->type = t;
goto ret; goto ret;
case OCLOSED:
case OCLOSE: case OCLOSE:
if(onearg(n, "%#O", n->op) < 0) if(onearg(n, "%#O", n->op) < 0)
goto error; goto error;
@ -934,11 +933,7 @@ reswitch:
yyerror("invalid operation: %#N (non-chan type %T)", n, t); yyerror("invalid operation: %#N (non-chan type %T)", n, t);
goto error; goto error;
} }
if(n->op == OCLOSED) { ok |= Etop;
n->type = types[TBOOL];
ok |= Erv;
} else
ok |= Etop;
goto ret; goto ret;
case OAPPEND: case OAPPEND:
@ -2377,8 +2372,9 @@ typecheckas2(Node *n)
n->op = OAS2MAPR; n->op = OAS2MAPR;
goto common; goto common;
case ORECV: case ORECV:
yyerror("cannot use multiple-value assignment for non-blocking receive; use select"); n->op = OAS2RECV;
goto out; n->right = n->rlist->n;
goto common;
case ODOTTYPE: case ODOTTYPE:
n->op = OAS2DOTTYPE; n->op = OAS2DOTTYPE;
r->op = ODOTTYPE2; r->op = ODOTTYPE2;

View File

@ -403,12 +403,11 @@ walkstmt(Node **np)
case OAS: case OAS:
case OAS2: case OAS2:
case OAS2DOTTYPE: case OAS2DOTTYPE:
case OAS2RECVCLOSED: case OAS2RECV:
case OAS2FUNC: case OAS2FUNC:
case OAS2MAPW: case OAS2MAPW:
case OAS2MAPR: case OAS2MAPR:
case OCLOSE: case OCLOSE:
case OCLOSED:
case OCOPY: case OCOPY:
case OCALLMETH: case OCALLMETH:
case OCALLINTER: case OCALLINTER:
@ -822,14 +821,13 @@ walkexpr(Node **np, NodeList **init)
n = liststmt(concat(concat(list1(r), ll), lpost)); n = liststmt(concat(concat(list1(r), ll), lpost));
goto ret; goto ret;
case OAS2RECVCLOSED: case OAS2RECV:
// a = <-c; b = closed(c) but atomic
*init = concat(*init, n->ninit); *init = concat(*init, n->ninit);
n->ninit = nil; n->ninit = nil;
r = n->rlist->n; r = n->rlist->n;
walkexprlistsafe(n->list, init); walkexprlistsafe(n->list, init);
walkexpr(&r->left, init); walkexpr(&r->left, init);
fn = chanfn("chanrecv3", 2, r->left->type); fn = chanfn("chanrecv2", 2, r->left->type);
r = mkcall1(fn, getoutargx(fn->type), init, r->left); r = mkcall1(fn, getoutargx(fn->type), init, r->left);
n->rlist->n = r; n->rlist->n = r;
n->op = OAS2FUNC; n->op = OAS2FUNC;
@ -1309,13 +1307,6 @@ walkexpr(Node **np, NodeList **init)
n = mkcall1(fn, T, init, n->left); n = mkcall1(fn, T, init, n->left);
goto ret; goto ret;
case OCLOSED:
// cannot use chanfn - closechan takes any, not chan any
fn = syslook("closedchan", 1);
argtype(fn, n->left->type);
n = mkcall1(fn, n->type, init, n->left);
goto ret;
case OMAKECHAN: case OMAKECHAN:
n = mkcall1(chanfn("makechan", 1, n->type), n->type, init, n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
typename(n->type->type), typename(n->type->type),

View File

@ -7,12 +7,6 @@
static int32 debug = 0; static int32 debug = 0;
enum
{
Wclosed = 0x0001, // writer has closed
Rclosed = 0x0002, // reader has seen close
};
typedef struct Link Link; typedef struct Link Link;
typedef struct WaitQ WaitQ; typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG; typedef struct SudoG SudoG;
@ -40,7 +34,7 @@ struct Hchan
uint32 qcount; // total data in the q uint32 qcount; // total data in the q
uint32 dataqsiz; // size of the circular q uint32 dataqsiz; // size of the circular q
uint16 elemsize; uint16 elemsize;
uint16 closed; // Wclosed Rclosed errorcount bool closed;
uint8 elemalign; uint8 elemalign;
Alg* elemalg; // interface for element type Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender Link* senddataq; // pointer for sender
@ -57,15 +51,26 @@ struct Link
byte elem[8]; // asynch queue data element (+ more) byte elem[8]; // asynch queue data element (+ more)
}; };
enum
{
// Scase.kind
CaseRecv,
CaseSend,
CaseDefault,
};
struct Scase struct Scase
{ {
Hchan* chan; // chan Hchan* chan; // chan
byte* pc; // return pc byte* pc; // return pc
uint16 send; // 0-recv 1-send 2-default uint16 kind;
uint16 so; // vararg of selected bool uint16 so; // vararg of selected bool
union { union {
byte elem[8]; // element (send) byte elem[2*sizeof(void*)]; // element (send)
byte* elemp; // pointer to element (recv) struct {
byte* elemp; // pointer to element (recv)
bool* receivedp; // pointer to received bool (recv2)
} recv;
} u; } u;
}; };
@ -183,7 +188,7 @@ runtime·chansend(Hchan *c, byte *ep, bool *pres)
runtime·lock(c); runtime·lock(c);
loop: loop:
if(c->closed & Wclosed) if(c->closed)
goto closed; goto closed;
if(c->dataqsiz > 0) if(c->dataqsiz > 0)
@ -228,7 +233,7 @@ loop:
return; return;
asynch: asynch:
if(c->closed & Wclosed) if(c->closed)
goto closed; goto closed;
if(c->qcount >= c->dataqsiz) { if(c->qcount >= c->dataqsiz) {
@ -269,7 +274,7 @@ closed:
} }
void void
runtime·chanrecv(Hchan* c, byte *ep, bool *pres, bool *closed) runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received)
{ {
SudoG *sg; SudoG *sg;
G *gp; G *gp;
@ -284,14 +289,12 @@ runtime·chanrecv(Hchan* c, byte *ep, bool *pres, bool *closed)
runtime·printf("chanrecv: chan=%p\n", c); runtime·printf("chanrecv: chan=%p\n", c);
runtime·lock(c); runtime·lock(c);
if(closed != nil)
*closed = false;
loop: loop:
if(c->dataqsiz > 0) if(c->dataqsiz > 0)
goto asynch; goto asynch;
if(c->closed & Wclosed) if(c->closed)
goto closed; goto closed;
sg = dequeue(&c->sendq, c); sg = dequeue(&c->sendq, c);
@ -305,14 +308,16 @@ loop:
runtime·unlock(c); runtime·unlock(c);
runtime·ready(gp); runtime·ready(gp);
if(pres != nil) if(selected != nil)
*pres = true; *selected = true;
if(received != nil)
*received = true;
return; return;
} }
if(pres != nil) { if(selected != nil) {
runtime·unlock(c); runtime·unlock(c);
*pres = false; *selected = false;
return; return;
} }
@ -331,18 +336,20 @@ loop:
if(ep != nil) if(ep != nil)
c->elemalg->copy(c->elemsize, ep, sg->elem); c->elemalg->copy(c->elemsize, ep, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil); c->elemalg->copy(c->elemsize, sg->elem, nil);
if(received != nil)
*received = true;
freesg(c, sg); freesg(c, sg);
runtime·unlock(c); runtime·unlock(c);
return; return;
asynch: asynch:
if(c->qcount <= 0) { if(c->qcount <= 0) {
if(c->closed & Wclosed) if(c->closed)
goto closed; goto closed;
if(pres != nil) { if(selected != nil) {
runtime·unlock(c); runtime·unlock(c);
*pres = false; *selected = false;
return; return;
} }
sg = allocsg(c); sg = allocsg(c);
@ -365,24 +372,22 @@ asynch:
freesg(c, sg); freesg(c, sg);
runtime·unlock(c); runtime·unlock(c);
runtime·ready(gp); runtime·ready(gp);
if(pres != nil) } else
*pres = true; runtime·unlock(c);
return;
}
runtime·unlock(c); if(selected != nil)
if(pres != nil) *selected = true;
*pres = true; if(received != nil)
*received = true;
return; return;
closed: closed:
if(closed != nil)
*closed = true;
if(ep != nil) if(ep != nil)
c->elemalg->copy(c->elemsize, ep, nil); c->elemalg->copy(c->elemsize, ep, nil);
c->closed |= Rclosed; if(selected != nil)
if(pres != nil) *selected = true;
*pres = true; if(received != nil)
*received = false;
runtime·unlock(c); runtime·unlock(c);
} }
@ -416,16 +421,16 @@ runtime·chanrecv1(Hchan* c, ...)
runtime·chanrecv(c, ae, nil, nil); runtime·chanrecv(c, ae, nil, nil);
} }
// chanrecv3(hchan *chan any) (elem any, closed bool); // chanrecv2(hchan *chan any) (elem any, received bool);
#pragma textflag 7 #pragma textflag 7
void void
runtime·chanrecv3(Hchan* c, ...) runtime·chanrecv2(Hchan* c, ...)
{ {
int32 o; int32 o;
byte *ae, *ac; byte *ae, *ac;
if(c == nil) if(c == nil)
runtime·panicstring("range over nil channel"); runtime·panicstring("receive from nil channel");
o = runtime·rnd(sizeof(c), Structrnd); o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o; ae = (byte*)&c + o;
@ -490,9 +495,35 @@ runtime·selectnbsend(Hchan *c, ...)
// //
#pragma textflag 7 #pragma textflag 7
void void
runtime·selectnbrecv(byte *v, Hchan *c, bool ok) runtime·selectnbrecv(byte *v, Hchan *c, bool selected)
{ {
runtime·chanrecv(c, v, &ok, nil); runtime·chanrecv(c, v, &selected, nil);
}
// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
//
// compiler implements
//
// select {
// case v = <-c:
// ... foo
// default:
// ... bar
// }
//
// as
//
// if c != nil && selectnbrecv(&v, c) {
// ... foo
// } else {
// ... bar
// }
//
#pragma textflag 7
void
runtime·selectnbrecv2(byte *v, bool *received, Hchan *c, bool selected)
{
runtime·chanrecv(c, v, &selected, received);
} }
static void newselect(int32, Select**); static void newselect(int32, Select**);
@ -556,22 +587,22 @@ runtime·selectsend(Select *sel, Hchan *c, ...)
eo = runtime·rnd(sizeof(sel), sizeof(c)); eo = runtime·rnd(sizeof(sel), sizeof(c));
eo = runtime·rnd(eo+sizeof(c), c->elemsize); eo = runtime·rnd(eo+sizeof(c), c->elemsize);
cas->so = runtime·rnd(eo+c->elemsize, Structrnd); cas->so = runtime·rnd(eo+c->elemsize, Structrnd);
cas->send = 1; cas->kind = CaseSend;
ae = (byte*)&sel + eo; ae = (byte*)&sel + eo;
c->elemalg->copy(c->elemsize, cas->u.elem, ae); c->elemalg->copy(c->elemsize, cas->u.elem, ae);
if(debug) if(debug)
runtime·printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n", runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n",
sel, cas->pc, cas->chan, cas->so, cas->send); sel, cas->pc, cas->chan, cas->so);
} }
// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag 7 #pragma textflag 7
void void
runtime·selectrecv(Select *sel, Hchan *c, ...) runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
{ {
int32 i, eo; int32 i;
Scase *cas; Scase *cas;
// nil cases do not compete // nil cases do not compete
@ -587,30 +618,60 @@ runtime·selectrecv(Select *sel, Hchan *c, ...)
cas->pc = runtime·getcallerpc(&sel); cas->pc = runtime·getcallerpc(&sel);
cas->chan = c; cas->chan = c;
eo = runtime·rnd(sizeof(sel), sizeof(c)); cas->so = (byte*)&selected - (byte*)&sel;
eo = runtime·rnd(eo+sizeof(c), sizeof(byte*)); cas->kind = CaseRecv;
cas->so = runtime·rnd(eo+sizeof(byte*), Structrnd); cas->u.recv.elemp = elem;
cas->send = 0; cas->u.recv.receivedp = nil;
cas->u.elemp = *(byte**)((byte*)&sel + eo);
if(debug) if(debug)
runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n", runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n",
sel, cas->pc, cas->chan, cas->so, cas->send); sel, cas->pc, cas->chan, cas->so);
}
// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
#pragma textflag 7
void
runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected)
{
int32 i;
Scase *cas;
// nil cases do not compete
if(c == nil)
return;
i = sel->ncase;
if(i >= sel->tcase)
runtime·throw("selectrecv: too many cases");
sel->ncase = i+1;
cas = runtime·mal(sizeof *cas);
sel->scase[i] = cas;
cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
cas->so = (byte*)&selected - (byte*)&sel;
cas->kind = CaseRecv;
cas->u.recv.elemp = elem;
cas->u.recv.receivedp = received;
if(debug)
runtime·printf("selectrecv2 s=%p pc=%p chan=%p so=%d elem=%p recv=%p\n",
sel, cas->pc, cas->chan, cas->so, cas->u.recv.elemp, cas->u.recv.receivedp);
} }
static void selectdefault(Select*, void*); static void selectdefault(Select*, void*, int32);
// selectdefault(sel *byte) (selected bool); // selectdefault(sel *byte) (selected bool);
#pragma textflag 7 #pragma textflag 7
void void
runtime·selectdefault(Select *sel, ...) runtime·selectdefault(Select *sel, bool selected)
{ {
selectdefault(sel, runtime·getcallerpc(&sel)); selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
} }
static void static void
selectdefault(Select *sel, void *callerpc) selectdefault(Select *sel, void *callerpc, int32 so)
{ {
int32 i; int32 i;
Scase *cas; Scase *cas;
@ -624,13 +685,12 @@ selectdefault(Select *sel, void *callerpc)
cas->pc = callerpc; cas->pc = callerpc;
cas->chan = nil; cas->chan = nil;
cas->so = runtime·rnd(sizeof(sel), Structrnd); cas->so = so;
cas->send = 2; cas->kind = CaseDefault;
cas->u.elemp = nil;
if(debug) if(debug)
runtime·printf("selectdefault s=%p pc=%p so=%d send=%d\n", runtime·printf("selectdefault s=%p pc=%p so=%d\n",
sel, cas->pc, cas->so, cas->send); sel, cas->pc, cas->so);
} }
static void static void
@ -747,8 +807,8 @@ loop:
cas = sel->scase[o]; cas = sel->scase[o];
c = cas->chan; c = cas->chan;
switch(cas->send) { switch(cas->kind) {
case 0: // recv case CaseRecv:
if(c->dataqsiz > 0) { if(c->dataqsiz > 0) {
if(c->qcount > 0) if(c->qcount > 0)
goto asyncrecv; goto asyncrecv;
@ -757,12 +817,12 @@ loop:
if(sg != nil) if(sg != nil)
goto syncrecv; goto syncrecv;
} }
if(c->closed & Wclosed) if(c->closed)
goto rclose; goto rclose;
break; break;
case 1: // send case CaseSend:
if(c->closed & Wclosed) if(c->closed)
goto sclose; goto sclose;
if(c->dataqsiz > 0) { if(c->dataqsiz > 0) {
if(c->qcount < c->dataqsiz) if(c->qcount < c->dataqsiz)
@ -774,7 +834,7 @@ loop:
} }
break; break;
case 2: // default case CaseDefault:
dfl = cas; dfl = cas;
break; break;
} }
@ -794,12 +854,12 @@ loop:
sg = allocsg(c); sg = allocsg(c);
sg->offset = o; sg->offset = o;
switch(cas->send) { switch(cas->kind) {
case 0: // recv case CaseRecv:
enqueue(&c->recvq, sg); enqueue(&c->recvq, sg);
break; break;
case 1: // send case CaseSend:
if(c->dataqsiz == 0) if(c->dataqsiz == 0)
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
enqueue(&c->sendq, sg); enqueue(&c->sendq, sg);
@ -821,7 +881,7 @@ loop:
if(sg == nil || i != sg->offset) { if(sg == nil || i != sg->offset) {
cas = sel->scase[i]; cas = sel->scase[i];
c = cas->chan; c = cas->chan;
if(cas->send) if(cas->kind == CaseSend)
dequeueg(&c->sendq, c); dequeueg(&c->sendq, c);
else else
dequeueg(&c->recvq, c); dequeueg(&c->recvq, c);
@ -841,12 +901,14 @@ loop:
} }
if(debug) if(debug)
runtime·printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n", runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d o=%d\n",
sel, c, cas, cas->send, o); sel, c, cas, cas->kind, o);
if(!cas->send) { if(cas->kind == CaseRecv) {
if(cas->u.elemp != nil) if(cas->u.recv.receivedp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); *cas->u.recv.receivedp = true;
if(cas->u.recv.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil); c->elemalg->copy(c->elemsize, sg->elem, nil);
} }
@ -855,8 +917,10 @@ loop:
asyncrecv: asyncrecv:
// can receive from buffer // can receive from buffer
if(cas->u.elemp != nil) if(cas->u.recv.receivedp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem); *cas->u.recv.receivedp = true;
if(cas->u.recv.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, c->recvdataq->elem);
c->elemalg->copy(c->elemsize, c->recvdataq->elem, nil); c->elemalg->copy(c->elemsize, c->recvdataq->elem, nil);
c->recvdataq = c->recvdataq->link; c->recvdataq = c->recvdataq->link;
c->qcount--; c->qcount--;
@ -886,8 +950,10 @@ syncrecv:
// can receive from sleeping sender (sg) // can receive from sleeping sender (sg)
if(debug) if(debug)
runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->u.elemp != nil) if(cas->u.recv.receivedp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); *cas->u.recv.receivedp = true;
if(cas->u.recv.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil); c->elemalg->copy(c->elemsize, sg->elem, nil);
gp = sg->g; gp = sg->g;
gp->param = sg; gp->param = sg;
@ -896,16 +962,17 @@ syncrecv:
rclose: rclose:
// read at end of closed channel // read at end of closed channel
if(cas->u.elemp != nil) if(cas->u.recv.receivedp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, nil); *cas->u.recv.receivedp = false;
c->closed |= Rclosed; if(cas->u.recv.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.recv.elemp, nil);
goto retc; goto retc;
syncsend: syncsend:
// can send to sleeping receiver (sg) // can send to sleeping receiver (sg)
if(debug) if(debug)
runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(c->closed & Wclosed) if(c->closed)
goto sclose; goto sclose;
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g; gp = sg->g;
@ -916,7 +983,6 @@ retc:
selunlock(sel); selunlock(sel);
// return to pc corresponding to chosen case // return to pc corresponding to chosen case
pc = cas->pc; pc = cas->pc;
as = (byte*)selp + cas->so; as = (byte*)selp + cas->so;
freesel(sel); freesel(sel);
@ -941,12 +1007,12 @@ runtime·closechan(Hchan *c)
runtime·gosched(); runtime·gosched();
runtime·lock(c); runtime·lock(c);
if(c->closed & Wclosed) { if(c->closed) {
runtime·unlock(c); runtime·unlock(c);
runtime·panicstring("close of closed channel"); runtime·panicstring("close of closed channel");
} }
c->closed |= Wclosed; c->closed = true;
// release all readers // release all readers
for(;;) { for(;;) {
@ -979,12 +1045,6 @@ runtime·chanclose(Hchan *c)
runtime·closechan(c); runtime·closechan(c);
} }
bool
runtime·chanclosed(Hchan *c)
{
return (c->closed & Rclosed) != 0;
}
int32 int32
runtime·chanlen(Hchan *c) runtime·chanlen(Hchan *c)
{ {
@ -997,15 +1057,6 @@ runtime·chancap(Hchan *c)
return c->dataqsiz; return c->dataqsiz;
} }
// closedchan(sel *byte) bool;
void
runtime·closedchan(Hchan *c, bool closed)
{
closed = runtime·chanclosed(c);
FLUSH(&closed);
}
static SudoG* static SudoG*
dequeue(WaitQ *q, Hchan *c) dequeue(WaitQ *q, Hchan *c)
{ {

View File

@ -70,22 +70,18 @@ func makechan(typ *byte, size uint32) (ch *byte) {
ch = (byte*)runtime·makechan_c(t->elem, size); ch = (byte*)runtime·makechan_c(t->elem, size);
} }
func chansend(ch *byte, val *byte, pres *bool) { func chansend(ch *byte, val *byte, selected *bool) {
runtime·chansend((Hchan*)ch, val, pres); runtime·chansend((Hchan*)ch, val, selected);
} }
func chanrecv(ch *byte, val *byte, pres *bool) { func chanrecv(ch *byte, val *byte, selected *bool, received *bool) {
runtime·chanrecv((Hchan*)ch, val, pres, nil); runtime·chanrecv((Hchan*)ch, val, selected, received);
} }
func chanclose(ch *byte) { func chanclose(ch *byte) {
runtime·chanclose((Hchan*)ch); runtime·chanclose((Hchan*)ch);
} }
func chanclosed(ch *byte) (r bool) {
r = runtime·chanclosed((Hchan*)ch);
}
func chanlen(ch *byte) (r int32) { func chanlen(ch *byte) (r int32) {
r = runtime·chanlen((Hchan*)ch); r = runtime·chanlen((Hchan*)ch);
} }

View File

@ -585,7 +585,6 @@ Hchan* runtime·makechan_c(Type*, int64);
void runtime·chansend(Hchan*, void*, bool*); void runtime·chansend(Hchan*, void*, bool*);
void runtime·chanrecv(Hchan*, void*, bool*, bool*); void runtime·chanrecv(Hchan*, void*, bool*, bool*);
void runtime·chanclose(Hchan*); void runtime·chanclose(Hchan*);
bool runtime·chanclosed(Hchan*);
int32 runtime·chanlen(Hchan*); int32 runtime·chanlen(Hchan*);
int32 runtime·chancap(Hchan*); int32 runtime·chancap(Hchan*);