Commit cb9b1038 authored by Ken Thompson's avatar Ken Thompson

select

R=r
APPROVED=r
DELTA=638  (433 added, 21 deleted, 184 changed)
OCL=13426
CL=13438
parent 485d1bb3
......@@ -255,6 +255,17 @@ loop:
breakpc = sbreak;
break;
case OSELECT:
gen(n->ninit);
sbreak = breakpc;
p1 = gbranch(AJMP, T); // goto test
breakpc = gbranch(AJMP, T); // break: goto done
patch(p1, pc); // test:
gen(n->nbody); // select() body
patch(breakpc, pc); // done:
breakpc = sbreak;
break;
case OASOP:
cgen_asop(n);
break;
......
......@@ -107,6 +107,7 @@ void compile(Node*);
void proglist(void);
void gen(Node*);
void swgen(Node*);
void selgen(Node*);
Node* lookdot(Node*, Node*, int);
void inarggen(void);
void agen_inter(Node*, Node*);
......
......@@ -219,8 +219,8 @@ enum
OLIST, OCMP,
OPTR, OARRAY,
ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL, OSELECT,
OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
OAS, OASOP, OCASE, OXCASE, OSCASE, OFALL, OXFALL,
OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY, OSELECT,
OOROR,
OANDAND,
......@@ -575,6 +575,7 @@ void walktype(Node*, int);
void walkbool(Node*);
Type* walkswitch(Node*, Type*(*)(Node*, Type*));
int casebody(Node*);
void walkselect(Node*);
int whatis(Node*);
void walkdot(Node*, int);
Node* ascompatee(int, Node**, Node**);
......@@ -585,7 +586,9 @@ Node* prcompat(Node*);
Node* nodpanic(long);
Node* newcompat(Node*);
Node* stringop(Node*, int);
Type* fixmap(Type*);
Node* mapop(Node*, int);
Type* fixchan(Type*);
Node* chanop(Node*, int);
Node* convas(Node*);
void arrayconv(Type*, Node*);
......
......@@ -338,8 +338,6 @@ complex_stmt:
| LSWITCH if_stmt
{
popdcl();
if(!casebody($2->nbody))
yyerror("switch statement must have case labels");
$$ = $2;
$$->op = OSWITCH;
//if($$->ninit != N && $$->ntest == N)
......
......@@ -7,6 +7,7 @@
6g sys.go
echo '1,/((/d
/))/+1,$d
g/init_.*_function/d
1,$s/foop/sys/g
1,$s/^[ ]*/ "/g
1,$s/$/\\n"/g
......
......@@ -603,6 +603,7 @@ opnames[] =
[OCALLINTER] = "CALLINTER",
[OCASE] = "CASE",
[OXCASE] = "XCASE",
[OSCASE] = "SCASE",
[OCMP] = "CMP",
[OFALL] = "FALL",
[OCONV] = "CONV",
......
......@@ -51,6 +51,11 @@ func chanrecv3(hchan *chan any) (elem any, pres bool);
func chansend1(hchan *chan any, elem any);
func chansend2(hchan *chan any, elem any) (pres bool);
func newselect(size uint32) (sel *byte);
func selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
func selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
func selectgo(sel *byte);
func gosched();
func goexit();
......@@ -112,6 +117,12 @@ export
chansend1
chansend2
// select
newselect
selectsend
selectrecv
selectgo
// go routines
gosched
goexit
......
This diff is collapsed.
This diff is collapsed.
......@@ -10,10 +10,13 @@ typedef struct Hchan Hchan;
typedef struct Link Link;
typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG;
typedef struct Select Select;
typedef struct Scase Scase;
struct SudoG
{
G* g; // g and selgen constitute
byte elem[8]; // synch data element
int64 selgen; // a weak pointer to g
SudoG* link;
};
......@@ -29,8 +32,8 @@ struct Hchan
uint32 elemsize;
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
uint32 eo; // vararg of element
uint32 po; // vararg of present bool
uint16 eo; // vararg of element
uint16 po; // vararg of present bool
Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender
Link* recvdataq; // pointer for receiver
......@@ -41,14 +44,33 @@ struct Hchan
struct Link
{
Link* link;
byte elem[8];
Link* link; // asynch queue circular linked list
byte elem[8]; // asynch queue data element
};
static SudoG* dequeue(WaitQ*, Hchan*);
static void enqueue(WaitQ*, SudoG*);
static SudoG* allocsg(Hchan*);
static void freesg(Hchan*, SudoG*);
struct Scase
{
Hchan* chan; // chan
byte* pc; // return pc
uint16 send; // 0-recv 1-send
uint16 so; // vararg of selected bool
byte elem[8]; // element
};
struct Select
{
uint16 tcase; // total count of scase[]
uint16 ncase; // currently filled scase[]
Scase scase[1]; // one per case
};
static SudoG* dequeue(WaitQ*, Hchan*);
static void enqueue(WaitQ*, SudoG*);
static SudoG* allocsg(Hchan*);
static void freesg(Hchan*, SudoG*);
static uint32 gcd(uint32, uint32);
static uint32 fastrand1(void);
static uint32 fastrand2(void);
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
void
......@@ -134,16 +156,15 @@ sys·chansend1(Hchan* c, ...)
sgr = dequeue(&c->recvq, c);
if(sgr != nil) {
gr = sgr->g;
freesg(c, sgr);
c->elemalg->copy(c->elemsize, sgr->elem, ae);
c->elemalg->copy(c->elemsize, gr->elem, ae);
gr = sgr->g;
gr->status = Grunnable;
return;
}
c->elemalg->copy(c->elemsize, g->elem, ae);
sgr = allocsg(c);
c->elemalg->copy(c->elemsize, sgr->elem, ae);
g->status = Gwaiting;
enqueue(&c->sendq, sgr);
sys·gosched();
......@@ -191,9 +212,8 @@ sys·chansend2(Hchan* c, ...)
sgr = dequeue(&c->recvq, c);
if(sgr != nil) {
gr = sgr->g;
freesg(c, sgr);
c->elemalg->copy(c->elemsize, sgr->elem, ae);
c->elemalg->copy(c->elemsize, gr->elem, ae);
gr->status = Grunnable;
*ap = true;
return;
......@@ -237,18 +257,20 @@ sys·chanrecv1(Hchan* c, ...)
sgs = dequeue(&c->sendq, c);
if(sgs != nil) {
gs = sgs->g;
freesg(c, sgs);
c->elemalg->copy(c->elemsize, ae, sgs->elem);
c->elemalg->copy(c->elemsize, ae, gs->elem);
gs = sgs->g;
gs->status = Grunnable;
freesg(c, sgs);
return;
}
sgs = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sgs);
sys·gosched();
c->elemalg->copy(c->elemsize, ae, g->elem);
c->elemalg->copy(c->elemsize, ae, sgs->elem);
freesg(c, sgs);
return;
asynch:
......@@ -291,11 +313,12 @@ sys·chanrecv2(Hchan* c, ...)
sgs = dequeue(&c->sendq, c);
if(sgs != nil) {
gs = sgs->g;
freesg(c, sgs);
c->elemalg->copy(c->elemsize, ae, sgs->elem);
c->elemalg->copy(c->elemsize, ae, gs->elem);
gs = sgs->g;
gs->status = Grunnable;
freesg(c, sgs);
*ap = true;
return;
}
......@@ -320,6 +343,150 @@ asynch:
*ap = true;
}
// newselect(size uint32) (sel *byte);
void
sys·newselect(int32 size, Select *sel)
{
int32 n;
n = 0;
if(size > 1)
n = size-1;
sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
sel->tcase = size;
sel->ncase = 0;
FLUSH(&sel);
if(debug) {
prints("newselect s=");
sys·printpointer(sel);
prints("\n");
}
}
// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
void
sys·selectsend(Select *sel, Hchan *c, ...)
{
int32 i, eo;
Scase *cas;
byte *as, *ae;
// return val, selected, is preset to false
if(c == nil)
return;
i = sel->ncase;
if(i >= sel->tcase)
throw("selectsend: too many cases");
sel->ncase = i+1;
cas = &sel->scase[i];
cas->pc = sys·getcallerpc(&sel);
cas->chan = c;
eo = rnd(sizeof(sel), sizeof(c));
eo = rnd(eo+sizeof(c), c->elemsize);
cas->so = rnd(eo+c->elemsize, 1);
cas->send = 1;
ae = (byte*)&sel + eo;
c->elemalg->copy(c->elemsize, cas->elem, ae);
as = (byte*)&sel + cas->so;
*as = false;
if(debug) {
prints("newselect s=");
sys·printpointer(sel);
prints(" pc=");
sys·printpointer(cas->pc);
prints(" chan=");
sys·printpointer(cas->chan);
prints(" po=");
sys·printint(cas->so);
prints(" send=");
sys·printint(cas->send);
prints("\n");
}
}
// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
void
sys·selectrecv(Select *sel, Hchan *c, ...)
{
throw("selectrecv");
}
// selectgo(sel *byte);
void
sys·selectgo(Select *sel)
{
uint32 p, o, i;
Scase *cas;
Hchan *c;
byte *ae, *as;
SudoG *sgr;
G *gr;
if(sel->ncase < 1) {
throw("selectgo: no cases");
}
// select a (relative) prime
for(i=0;; i++) {
p = fastrand1();
if(gcd(p, sel->ncase) == 1)
break;
if(i > 1000) {
throw("selectgo: failed to select prime");
}
}
o = fastrand2();
p %= sel->ncase;
o %= sel->ncase;
// pass 1 - look for something that can go
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
c = cas->chan;
if(cas->send) {
if(c->dataqsiz > 0) {
throw("selectgo: asynch");
}
sgr = dequeue(&c->recvq, c);
if(sgr == nil)
continue;
c->elemalg->copy(c->elemsize, sgr->elem, cas->elem);
gr = sgr->g;
gr->status = Grunnable;
goto retc;
}
o += p;
if(o >= sel->ncase)
o -= sel->ncase;
}
if(debug) {
prints("selectgo s=");
sys·printpointer(sel);
prints(" p=");
sys·printpointer((void*)p);
prints("\n");
}
throw("selectgo");
retc:
sys·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
*as = true;
}
static SudoG*
dequeue(WaitQ *q, Hchan *c)
{
......@@ -377,3 +544,41 @@ freesg(Hchan *c, SudoG *sg)
sg->link = c->free;
c->free = sg;
}
static uint32
gcd(uint32 u, uint32 v)
{
for(;;) {
if(u > v) {
if(v == 0)
return u;
u = u%v;
continue;
}
if(u == 0)
return v;
v = v%u;
}
}
static uint32
fastrand1(void)
{
static uint32 x = 0x49f6428aUL;
x += x;
if(x & 0x80000000L)
x ^= 0x88888eefUL;
return x;
}
static uint32
fastrand2(void)
{
static uint32 x = 0x49f6428aUL;
x += x;
if(x & 0x80000000L)
x ^= 0xfafd871bUL;
return x;
}
......@@ -110,7 +110,6 @@ struct G
int32 status;
int32 goid;
int64 selgen; // valid sudog pointer
byte elem[8]; // transfer element for chan
};
struct M
{
......@@ -205,6 +204,7 @@ void sys·write(int32, void*, int32);
void sys·breakpoint(void);
uint8* sys·mmap(byte*, uint32, int32, int32, int32, uint32);
void sys·memclr(byte*, uint32);
void sys·setcallerpc(void*, void*);
void* sys·getcallerpc(void*);
void sys·sigaction(int64, void*, void*);
void sys·rt_sigaction(int64, void*, void*, uint64);
......
......@@ -110,6 +110,12 @@ TEXT sys·memclr(SB),1,$-8
RET
TEXT sys·getcallerpc+0(SB),1,$0
MOVQ x+0(FP),AX
MOVQ -8(AX),AX
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
RET
TEXT sys·setcallerpc+0(SB),1,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
......@@ -114,6 +114,12 @@ TEXT sys·memclr(SB),1,$0-16
RET
TEXT sys·getcallerpc+0(SB),1,$0
MOVQ x+0(FP),AX
MOVQ -8(AX),AX
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
RET
TEXT sys·setcallerpc+0(SB),1,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment