start of select
random bugs fixed

SVN=128149
diff --git a/src/cmd/6g/gen.c b/src/cmd/6g/gen.c
index 6dfafc4..3bab742 100644
--- a/src/cmd/6g/gen.c
+++ b/src/cmd/6g/gen.c
@@ -902,6 +902,11 @@
 
 		case TPTR32:
 		case TPTR64:
+			if(isptrto(tl, TSTRING)) {
+				nr->val.sval = mal(8);
+				nr->val.ctype = CTSTR;
+				break;
+			}
 			nr->val.ctype = CTNIL;
 			nr->val.vval = 0;
 			break;
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 12a7ef8..1d8b921 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -20,9 +20,13 @@
 		goto bad1;
 
 	case Wlitnil:
-		if(isptr[et] || et == TINTER)
-			break;
-		goto bad1;
+		if(!isptr[et] && et != TINTER)
+			goto bad1;
+		if(isptrto(t, TSTRING)) {
+			n->val.sval = mal(8);
+			n->val.ctype = CTSTR;
+		}
+		break;
 
 	case Wlitstr:
 		if(isptrto(t, TSTRING))
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 1002f2b..9a49f6f 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -219,7 +219,7 @@
 	OLIST, OCMP,
 	OPTR, OARRAY,
 	ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
-	OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
+	OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL, OSELECT,
 	OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
 
 	OOROR,
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index c0d0112..13c08ba 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -18,7 +18,7 @@
 %token			LMAP LCHAN LINTERFACE LFUNC LSTRUCT
 %token			LCOLAS LFALL LRETURN
 %token			LNEW LLEN
-%token			LVAR LTYPE LCONST LCONVERT
+%token			LVAR LTYPE LCONST LCONVERT LSELECT
 %token			LFOR LIF LELSE LSWITCH LCASE LDEFAULT
 %token			LBREAK LCONTINUE LGO LGOTO LRANGE
 %token			LOROR LANDAND LEQ LNE LLE LLT LGE LGT
@@ -37,7 +37,7 @@
 %type	<node>		Astmt Bstmt Cstmt Dstmt
 %type	<node>		for_stmt for_body for_header
 %type	<node>		if_stmt if_body if_header
-%type	<node>		range_header range_body range_stmt
+%type	<node>		range_header range_body range_stmt select_stmt
 %type	<node>		simple_stmt osimple_stmt semi_stmt
 %type	<node>		expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
 %type	<node>		name name_name new_name new_name_list_r conexpr
@@ -360,6 +360,11 @@
 		//if($$->ninit != N && $$->ntest == N)
 		//	yyerror("if conditional should not be missing");
 	}
+|	LSELECT select_stmt
+	{
+		popdcl();
+		$$ = $2;
+	}
 |	LRANGE range_stmt
 	{
 		popdcl();
@@ -529,6 +534,15 @@
 		$$ = $2;
 	}
 
+select_stmt:
+	{
+		markdcl();
+	}
+	compound_stmt
+	{
+		$$ = nod(OSELECT, $2, N);
+	}
+
 /*
  * expressions
  */
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 1923308..b12ab05 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -962,20 +962,20 @@
 	"string",	LBASETYPE,	TSTRING,
 
 	"any",		LBASETYPE,	TANY,
+	"sys",		LPACK,		Txxx,
 
 /* keywords */
-//	"any",		LANY,		Txxx,
 	"break",	LBREAK,		Txxx,
 	"case",		LCASE,		Txxx,
 	"chan",		LCHAN,		Txxx,
 	"const",	LCONST,		Txxx,
 	"continue",	LCONTINUE,	Txxx,
-	"convert",	LCONVERT,	Txxx,
+	"convert",	LCONVERT,	Txxx,		// should be a var
 	"default",	LDEFAULT,	Txxx,
 	"else",		LELSE,		Txxx,
 	"export",	LEXPORT,	Txxx,
 	"fallthrough",	LFALL,		Txxx,
-	"false",	LFALSE,		Txxx,
+	"false",	LFALSE,		Txxx,		// should be a var
 	"for",		LFOR,		Txxx,
 	"func",		LFUNC,		Txxx,
 	"go",		LGO,		Txxx,
@@ -985,20 +985,20 @@
 	"interface",	LINTERFACE,	Txxx,
 	"iota",		LIOTA,		Txxx,
 	"map",		LMAP,		Txxx,
-	"new",		LNEW,		Txxx,
-	"len",		LLEN,		Txxx,
-	"nil",		LNIL,		Txxx,
+	"new",		LNEW,		Txxx,		// should be a var
+	"len",		LLEN,		Txxx,		// should be a var
+	"nil",		LNIL,		Txxx,		// should be a var
 	"package",	LPACKAGE,	Txxx,
-	"panic",	LPANIC,		Txxx,
-	"print",	LPRINT,		Txxx,
+	"panic",	LPANIC,		Txxx,		// temp
+	"print",	LPRINT,		Txxx,		// temp
 	"range",	LRANGE,		Txxx,
 	"return",	LRETURN,	Txxx,
+	"select",	LSELECT,	Txxx,
 	"struct",	LSTRUCT,	Txxx,
 	"switch",	LSWITCH,	Txxx,
-	"true",		LTRUE,		Txxx,
+	"true",		LTRUE,		Txxx,		// should be a var
 	"type",		LTYPE,		Txxx,
 	"var",		LVAR,		Txxx,
-	"sys",		LPACK,		Txxx,
 
 	"notwithstanding",		LIGNORE,	Txxx,
 	"thetruthofthematter",		LIGNORE,	Txxx,
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 17f837e..b9c0da5 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -659,6 +659,7 @@
 	[OI2I]		= "I2I",
 	[OSLICE]	= "SLICE",
 	[OSUB]		= "SUB",
+	[OSELECT]	= "SELECT",
 	[OSWITCH]	= "SWITCH",
 	[OTYPE]		= "TYPE",
 	[OVAR]		= "VAR",
diff --git a/src/runtime/chan.c b/src/runtime/chan.c
index 6282c78..99f9b23 100644
--- a/src/runtime/chan.c
+++ b/src/runtime/chan.c
@@ -8,6 +8,21 @@
 
 typedef	struct	Hchan	Hchan;
 typedef	struct	Link	Link;
+typedef	struct	WaitQ	WaitQ;
+typedef	struct	SudoG	SudoG;
+
+struct	SudoG
+{
+	G*	g;		// g and selgen constitute
+	int64	selgen;		// a weak pointer to g
+	SudoG*	link;
+};
+
+struct	WaitQ
+{
+	SudoG*	first;
+	SudoG*	last;
+};
 
 struct	Hchan
 {
@@ -21,6 +36,7 @@
 	Link*	recvdataq;		// pointer for receiver
 	WaitQ	recvq;			// list of recv waiters
 	WaitQ	sendq;			// list of send waiters
+	SudoG*	free;			// freelist
 };
 
 struct	Link
@@ -29,6 +45,11 @@
 	byte	elem[8];
 };
 
+static SudoG*	dequeue(WaitQ*, Hchan*);
+static void	enqueue(WaitQ*, SudoG*);
+static SudoG*	allocsg(Hchan*);
+static void	freesg(Hchan*, SudoG*);
+
 // newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
 void
 sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
@@ -97,7 +118,8 @@
 sys·chansend1(Hchan* c, ...)
 {
 	byte *ae;
-	G *gr;
+	SudoG *sgr;
+	G* gr;
 
 	ae = (byte*)&c + c->eo;
 	if(debug) {
@@ -110,30 +132,39 @@
 	if(c->dataqsiz > 0)
 		goto asynch;
 
-	gr = dequeue(&c->recvq);
-	if(gr != nil) {
+	sgr = dequeue(&c->recvq, c);
+	if(sgr != nil) {
+		gr = sgr->g;
+		freesg(c, sgr);
+
 		c->elemalg->copy(c->elemsize, gr->elem, ae);
 		gr->status = Grunnable;
 		return;
 	}
+
 	c->elemalg->copy(c->elemsize, g->elem, ae);
+	sgr = allocsg(c);
 	g->status = Gwaiting;
-	enqueue(&c->sendq, g);
+	enqueue(&c->sendq, sgr);
 	sys·gosched();
 	return;
 
 asynch:
 	while(c->qcount >= c->dataqsiz) {
+		sgr = allocsg(c);
 		g->status = Gwaiting;
-		enqueue(&c->sendq, g);
+		enqueue(&c->sendq, sgr);
 		sys·gosched();
 	}
 	c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
 	c->senddataq = c->senddataq->link;
 	c->qcount++;
-	gr = dequeue(&c->recvq);
-	if(gr != nil)
+	sgr = dequeue(&c->recvq, c);
+	if(sgr != nil) {
+		gr = sgr->g;
+		freesg(c, sgr);
 		gr->status = Grunnable;
+	}
 }
 
 // chansend2(hchan *chan any, elem any) (pres bool);
@@ -141,6 +172,7 @@
 sys·chansend2(Hchan* c, ...)
 {
 	byte *ae, *ap;
+	SudoG *sgr;
 	G *gr;
 
 	ae = (byte*)&c + c->eo;
@@ -156,8 +188,11 @@
 	if(c->dataqsiz > 0)
 		goto asynch;
 
-	gr = dequeue(&c->recvq);
-	if(gr != nil) {
+	sgr = dequeue(&c->recvq, c);
+	if(sgr != nil) {
+		gr = sgr->g;
+		freesg(c, sgr);
+
 		c->elemalg->copy(c->elemsize, gr->elem, ae);
 		gr->status = Grunnable;
 		*ap = true;
@@ -174,9 +209,12 @@
 	c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
 	c->senddataq = c->senddataq->link;
 	c->qcount++;
-	gr = dequeue(&c->recvq);
-	if(gr != nil)
+	sgr = dequeue(&c->recvq, c);
+	if(gr != nil) {
+		gr = sgr->g;
+		freesg(c, sgr);
 		gr->status = Grunnable;
+	}
 	*ap = true;
 }
 
@@ -185,6 +223,7 @@
 sys·chanrecv1(Hchan* c, ...)
 {
 	byte *ae;
+	SudoG *sgs;
 	G *gs;
 
 	ae = (byte*)&c + c->eo;
@@ -196,30 +235,39 @@
 	if(c->dataqsiz > 0)
 		goto asynch;
 
-	gs = dequeue(&c->sendq);
-	if(gs != nil) {
+	sgs = dequeue(&c->sendq, c);
+	if(sgs != nil) {
+		gs = sgs->g;
+		freesg(c, sgs);
+
 		c->elemalg->copy(c->elemsize, ae, gs->elem);
 		gs->status = Grunnable;
 		return;
 	}
+	sgs = allocsg(c);
 	g->status = Gwaiting;
-	enqueue(&c->recvq, g);
+	enqueue(&c->recvq, sgs);
 	sys·gosched();
 	c->elemalg->copy(c->elemsize, ae, g->elem);
 	return;
 
 asynch:
 	while(c->qcount <= 0) {
+		sgs = allocsg(c);
 		g->status = Gwaiting;
-		enqueue(&c->recvq, g);
+		enqueue(&c->recvq, sgs);
 		sys·gosched();
 	}
 	c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
 	c->recvdataq = c->recvdataq->link;
 	c->qcount--;
-	gs = dequeue(&c->sendq);
-	if(gs != nil)
+	sgs = dequeue(&c->sendq, c);
+	if(gs != nil) {
+		gs = sgs->g;
+		freesg(c, sgs);
+
 		gs->status = Grunnable;
+	}
 }
 
 // chanrecv2(hchan *chan any) (elem any, pres bool);
@@ -227,6 +275,7 @@
 sys·chanrecv2(Hchan* c, ...)
 {
 	byte *ae, *ap;
+	SudoG *sgs;
 	G *gs;
 
 	ae = (byte*)&c + c->eo;
@@ -240,8 +289,11 @@
 	if(c->dataqsiz > 0)
 		goto asynch;
 
-	gs = dequeue(&c->sendq);
-	if(gs != nil) {
+	sgs = dequeue(&c->sendq, c);
+	if(sgs != nil) {
+		gs = sgs->g;
+		freesg(c, sgs);
+
 		c->elemalg->copy(c->elemsize, ae, gs->elem);
 		gs->status = Grunnable;
 		*ap = true;
@@ -258,8 +310,70 @@
 	c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
 	c->recvdataq = c->recvdataq->link;
 	c->qcount--;
-	gs = dequeue(&c->sendq);
-	if(gs != nil)
+	sgs = dequeue(&c->sendq, c);
+	if(sgs != nil) {
+		gs = sgs->g;
+		freesg(c, sgs);
+
 		gs->status = Grunnable;
+	}
 	*ap = true;
 }
+
+static SudoG*
+dequeue(WaitQ *q, Hchan *c)
+{
+	SudoG *sgp;
+
+loop:
+	sgp = q->first;
+	if(sgp == nil)
+		return nil;
+	q->first = sgp->link;
+
+	// if sgp is stale, ignore it
+	if(sgp->selgen != sgp->g->selgen) {
+prints("INVALID PSEUDOG POINTER\n");
+		freesg(c, sgp);
+		goto loop;
+	}
+
+	// invalidate any others
+	sgp->g->selgen++;
+	return sgp;
+}
+
+static void
+enqueue(WaitQ *q, SudoG *sgp)
+{
+	sgp->link = nil;
+	if(q->first == nil) {
+		q->first = sgp;
+		q->last = sgp;
+		return;
+	}
+	q->last->link = sgp;
+	q->last = sgp;
+}
+
+static SudoG*
+allocsg(Hchan *c)
+{
+	SudoG* sg;
+
+	sg = c->free;
+	if(sg != nil) {
+		c->free = sg->link;
+	} else
+		sg = mal(sizeof(*sg));
+	sg->selgen = g->selgen;
+	sg->g = g;
+	return sg;
+}
+
+static void
+freesg(Hchan *c, SudoG *sg)
+{
+	sg->link = c->free;
+	c->free = sg;
+}
diff --git a/src/runtime/proc.c b/src/runtime/proc.c
index 807c70b..ecd4ced 100644
--- a/src/runtime/proc.c
+++ b/src/runtime/proc.c
@@ -254,28 +254,3 @@
 
 	*(int32*)234 = 123;	// never return
 }
-
-G*
-dequeue(WaitQ *q)
-{
-	G *gp;
-
-	gp = q->first;
-	if(gp == nil)
-		return nil;
-	q->first = gp->qlink;
-	return gp;
-}
-
-void
-enqueue(WaitQ *q, G *gp)
-{
-	gp->qlink = nil;
-	if(q->first == nil) {
-		q->first = gp;
-		q->last = gp;
-		return;
-	}
-	q->last->qlink = gp;
-	q->last = gp;
-}
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index b1e8b69..df14b76 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -42,7 +42,6 @@
 typedef	struct	M		M;
 typedef struct	Stktop		Stktop;
 typedef	struct	Alg		Alg;
-typedef	struct	WaitQ		WaitQ;
 
 /*
  * per cpu declaration
@@ -108,9 +107,9 @@
 	byte*	stack0;		// first stack segment
 	Gobuf	sched;
 	G*	alllink;	// on allq
-	G*	qlink;		// on wait q
 	int32	status;
 	int32	goid;
+	int64	selgen;		// valid sudog pointer
 	byte	elem[8];	// transfer element for chan
 };
 struct	M
@@ -126,11 +125,6 @@
 	int32	siz1;
 	int32	siz2;
 };
-struct	WaitQ
-{
-	G*	first;
-	G*	last;
-};
 struct	Stktop
 {
 	uint8*	oldbase;
@@ -176,8 +170,6 @@
 void	dump(byte*, int32);
 int32	runetochar(byte*, int32);
 int32	chartorune(uint32*, byte*);
-G*	dequeue(WaitQ*);
-void	enqueue(WaitQ*, G*);
 
 /*
  * very low level c-called
diff --git a/test/chan/powser1.go b/test/chan/powser1.go
index abafc46..65ea0db 100644
--- a/test/chan/powser1.go
+++ b/test/chan/powser1.go
@@ -233,24 +233,6 @@
 var Ones PS
 var Twos PS
 
-// print eval in floating point of PS at x=c to n terms
-func
-Evaln(c *rat, U PS, n int)
-{
-	xn := float64(1);
-	x := float64(c.num)/float64(c.den);
-	val := float64(0);
-	for i:=0; i<n; i++ {
-		u := get(U);
-		if end(u) != 0 {
-			break;
-		}
-		val = val + x * float64(u.num)/float64(u.den);
-		xn = xn*x;
-	}
-	print val, "\n";
-}
-
 func mkPS() *dch {
 	return mkdch()
 }
@@ -335,8 +317,25 @@
 	return i2tor(u.den, u.num);
 }
 
-// Print n terms of a power series
+// print eval in floating point of PS at x=c to n terms
+func
+Evaln(c *rat, U PS, n int)
+{
+	xn := float64(1);
+	x := float64(c.num)/float64(c.den);
+	val := float64(0);
+	for i:=0; i<n; i++ {
+		u := get(U);
+		if end(u) != 0 {
+			break;
+		}
+		val = val + x * float64(u.num)/float64(u.den);
+		xn = xn*x;
+	}
+	print val, "\n";
+}
 
+// Print n terms of a power series
 func Printn(U PS, n int){
 	done := false;
 	for ; !done && n>0; n-- {
@@ -352,7 +351,6 @@
 }
 
 // Evaluate n terms of power series U at x=c
-
 func eval(c *rat, U PS, n int) *rat{
 	if n==0 { return zero }
 	y := get(U);