From 265e73ee14ebfedc027871cd153f0b90c6665070 Mon Sep 17 00:00:00 2001
From: Rob Pike <r@golang.org>
Date: Fri, 17 Oct 2008 18:06:29 -0700
Subject: [PATCH] beginnings of reflection values.

R=rsc
DELTA=421  (357 added, 17 deleted, 47 changed)
OCL=17388
CL=17401
---
 usr/r/reflect/Makefile     |  11 ++-
 usr/r/reflect/cast_amd64.s | 133 +++++++++++++++++++++++++++++++++++++
 usr/r/reflect/gencast.sh   |  36 ++++++++++
 usr/r/reflect/main.go      | 102 +++++++++++++++++++---------
 usr/r/reflect/tostring.go  |  77 ++++++++++++++++-----
 usr/r/reflect/type.go      | 114 ++++++++++++++++++++++++++-----
 6 files changed, 408 insertions(+), 65 deletions(-)
 create mode 100644 usr/r/reflect/cast_amd64.s
 create mode 100755 usr/r/reflect/gencast.sh

diff --git a/usr/r/reflect/Makefile b/usr/r/reflect/Makefile
index ffd1f14bcc..1d999f4e0a 100644
--- a/usr/r/reflect/Makefile
+++ b/usr/r/reflect/Makefile
@@ -3,7 +3,7 @@
 # license that can be found in the LICENSE file.
 
 # DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m reflect tostring.go type.go
+# gobuild -m reflect tostring.go type.go value.go cast_amd64.s
 O=6
 GC=$(O)g
 CC=$(O)c -w
@@ -32,16 +32,23 @@ clean:
 
 O1=\
 	type.$O\
+	cast_amd64.$O\
 
 O2=\
+	value.$O\
+
+O3=\
 	tostring.$O\
 
-$(PKG): a1 a2
+$(PKG): a1 a2 a3
 a1:	$(O1)
 	$(AR) grc $(PKG) $(O1)
 a2:	$(O2)
 	$(AR) grc $(PKG) $(O2)
+a3:	$(O3)
+	$(AR) grc $(PKG) $(O3)
 
 $(O1): nuke
 $(O2): a1
+$(O3): a2
 
diff --git a/usr/r/reflect/cast_amd64.s b/usr/r/reflect/cast_amd64.s
new file mode 100644
index 0000000000..1de31dd041
--- /dev/null
+++ b/usr/r/reflect/cast_amd64.s
@@ -0,0 +1,133 @@
+// Conversion operators - really just casts
+// *** Created by gencast.sh - Do Not Edit ***
+
+TEXT reflect·AddrToPtrAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrAddrToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrInt8(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrInt8ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrInt16(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrInt16ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrInt32(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrInt32ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrInt64(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrInt64ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrUint8(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrUint8ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrUint16(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrUint16ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrUint32(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrUint32ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrUint64(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrUint64ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrFloat32(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrFloat32ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrFloat64(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrFloat64ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrFloat80(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrFloat80ToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·AddrToPtrString(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrStringToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
diff --git a/usr/r/reflect/gencast.sh b/usr/r/reflect/gencast.sh
new file mode 100755
index 0000000000..e3871a5316
--- /dev/null
+++ b/usr/r/reflect/gencast.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# Copyright 2009 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+awk '
+BEGIN {
+	print("// Conversion operators - really just casts")
+	print("// *** Created by gencast.sh - Do Not Edit ***\n")}
+{
+	print("TEXT reflect·AddrToPtr" $0 "(SB),7,$-8")
+	print("\tMOVQ	8(SP), AX")
+	print("\tMOVQ	AX, 16(SP)")
+	print("\tRET")
+	print("")
+	print("TEXT reflect·Ptr" $0 "ToAddr(SB),7,$-8")
+	print("\tMOVQ	8(SP), AX")
+	print("\tMOVQ	AX, 16(SP)")
+	print("\tRET")
+	print("")
+}
+' > cast_$GOARCH.s << '!'
+Addr
+Int8
+Int16
+Int32
+Int64
+Uint8
+Uint16
+Uint32
+Uint64
+Float32
+Float64
+Float80
+String
+!
diff --git a/usr/r/reflect/main.go b/usr/r/reflect/main.go
index 0348cef9fe..1967ed7c39 100644
--- a/usr/r/reflect/main.go
+++ b/usr/r/reflect/main.go
@@ -8,37 +8,79 @@ import (
 	"reflect"
 )
 
+func typedump(s string) {
+	t := reflect.ParseTypeString(s);
+	print(reflect.TypeToString(t),"; size = ", t.Size(), "\n");
+}
+
+func valuedump(s string) {
+	t := reflect.ParseTypeString(s);
+	v := reflect.NewInitValue(t);
+	switch v.Kind() {
+	case reflect.Int8Kind:
+		v.(reflect.Int8Value).Put(8);
+	case reflect.Int16Kind:
+		v.(reflect.Int16Value).Put(16);
+	case reflect.Int32Kind:
+		v.(reflect.Int32Value).Put(32);
+	case reflect.Int64Kind:
+		v.(reflect.Int64Value).Put(64);
+	case reflect.Uint8Kind:
+		v.(reflect.Uint8Value).Put(8);
+	case reflect.Uint16Kind:
+		v.(reflect.Uint16Value).Put(16);
+	case reflect.Uint32Kind:
+		v.(reflect.Uint32Value).Put(32);
+	case reflect.Uint64Kind:
+		v.(reflect.Uint64Value).Put(64);
+	case reflect.Float32Kind:
+		v.(reflect.Float32Value).Put(320.0);
+	case reflect.Float64Kind:
+		v.(reflect.Float32Value).Put(640.0);
+	case reflect.StringKind:
+		v.(reflect.StringValue).Put("stringy cheese");
+	}
+	print(s, " value = ", reflect.ValueToString(v), "\n");
+}
+
 func main() {
 	var s string;
 	var t reflect.Type;
-
-	t = reflect.ParseTypeString("int8");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("**int8");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("**P.integer");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("[32]int32");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("[]int8");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("map[string]int32");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("*chan<-string");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("struct {c *chan *int32; d float32}");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("*(a int8, b int32)");
-	s = reflect.ToString(t); print(s, "\n");
-
-	t = reflect.ParseTypeString("struct {c *(? *chan *P.integer, ? *int8)}");
-	s = reflect.ToString(t); print(s, "\n");
+	
+	typedump("int8");
+	typedump("int16");
+	typedump("int32");
+	typedump("int64");
+	typedump("uint8");
+	typedump("uint16");
+	typedump("uint32");
+	typedump("uint64");
+	typedump("float32");
+	typedump("float64");
+	typedump("float80");
+	typedump("int8");
+	typedump("**int8");
+	typedump("**P.integer");
+	typedump("[32]int32");
+	typedump("[]int8");
+	typedump("*map[string]int32");
+	typedump("*chan<-string");
+	typedump("struct {c *chan *int32; d float32}");
+	typedump("*(a int8, b int32)");
+	typedump("struct {c *(? *chan *P.integer, ? *int8)}");
+	typedump("struct {a int8; b int32}");
+	typedump("struct {a int8; b int8; b int32}");
+	typedump("struct {a int8; b int8; c int8; b int32}");
+	typedump("struct {a int8; b int8; c int8; d int8; b int32}");
+	typedump("struct {a int8; b int8; c int8; d int8; e int8; b int32}");
+	
+	valuedump("int8");
+	valuedump("int16");
+	valuedump("int32");
+	valuedump("int64");
+	valuedump("uint8");
+	valuedump("uint16");
+	valuedump("uint32");
+	valuedump("uint64");
+	valuedump("string");
 }
diff --git a/usr/r/reflect/tostring.go b/usr/r/reflect/tostring.go
index 09b6945a2a..0449a6e9e0 100644
--- a/usr/r/reflect/tostring.go
+++ b/usr/r/reflect/tostring.go
@@ -12,14 +12,15 @@ import (
 	"strings";
 )
 
-export func ToString(typ Type) string
+export func TypeToString(typ Type) string
+export func ValueToString(val Value) string
 
-func FieldsToString(t Type, sep string) string {
+func TypeFieldsToString(t Type, sep string) string {
 	s := t.(StructType);
 	var str string;
 	for i := 0; i < s.Len(); i++ {
 		str1, t := s.Field(i);
-		str1 +=  " " + ToString(t);
+		str1 +=  " " + TypeToString(t);
 		if i < s.Len() - 1 {
 			str1 += sep + " ";
 		}
@@ -28,7 +29,7 @@ func FieldsToString(t Type, sep string) string {
 	return str;
 }
 
-func ToString(typ Type) string {
+func TypeToString(typ Type) string {
 	var str string;
 	switch(typ.Kind()) {
 	case MissingKind:
@@ -59,7 +60,7 @@ func ToString(typ Type) string {
 		return "string";
 	case PtrKind:
 		p := typ.(PtrType);
-		return "*" + ToString(p.Sub());
+		return "*" + TypeToString(p.Sub());
 	case ArrayKind:
 		a := typ.(ArrayType);
 		if a.Len() < 0 {
@@ -67,11 +68,11 @@ func ToString(typ Type) string {
 		} else {
 			str = "[" + strings.itoa(a.Len()) +  "]"
 		}
-		return str + ToString(a.Elem());
+		return str + TypeToString(a.Elem());
 	case MapKind:
 		m := typ.(MapType);
-		str = "map[" + ToString(m.Key()) + "]";
-		return str + ToString(m.Elem());
+		str = "map[" + TypeToString(m.Key()) + "]";
+		return str + TypeToString(m.Elem());
 	case ChanKind:
 		c := typ.(ChanType);
 		switch c.Dir() {
@@ -82,23 +83,67 @@ func ToString(typ Type) string {
 		case BothDir:
 			str = "chan";
 		default:
-			panicln("reflect.ToString: unknown chan direction");
+			panicln("reflect.TypeToString: unknown chan direction");
 		}
-		return str + ToString(c.Elem());
+		return str + TypeToString(c.Elem());
 	case StructKind:
-		return "struct{" + FieldsToString(typ, ";") + "}";
+		return "struct{" + TypeFieldsToString(typ, ";") + "}";
 	case InterfaceKind:
-		return "interface{" + FieldsToString(typ, ";") + "}";
+		return "interface{" + TypeFieldsToString(typ, ";") + "}";
 	case FuncKind:
 		f := typ.(FuncType);
 		str = "func";
-		str += "(" + FieldsToString(f.In(), ",") + ")";
+		str += "(" + TypeFieldsToString(f.In(), ",") + ")";
 		if f.Out() != nil {
-			str += "(" + FieldsToString(f.Out(), ",") + ")";
+			str += "(" + TypeFieldsToString(f.Out(), ",") + ")";
 		}
 		return str;
 	default:
-		panicln("reflect.ToString: can't print type ", typ.Kind());
+		panicln("reflect.TypeToString: can't print type ", typ.Kind());
 	}
-	return "reflect.ToString: can't happen";
+	return "reflect.TypeToString: can't happen";
+}
+
+// TODO: want an unsigned one too
+func integer(v int64) string {
+	return strings.itol(v);
+}
+
+func ValueToString(val Value) string {
+	var str string;
+	typ := val.Type();
+	switch(val.Kind()) {
+	case MissingKind:
+		return "missing";
+	case Int8Kind:
+		return integer(int64(val.(Int8Value).Get()));
+	case Int16Kind:
+		return integer(int64(val.(Int16Value).Get()));
+	case Int32Kind:
+		return integer(int64(val.(Int32Value).Get()));
+	case Int64Kind:
+		return integer(int64(val.(Int64Value).Get()));
+	case Uint8Kind:
+		return integer(int64(val.(Uint8Value).Get()));
+	case Uint16Kind:
+		return integer(int64(val.(Uint16Value).Get()));
+	case Uint32Kind:
+		return integer(int64(val.(Uint32Value).Get()));
+	case Uint64Kind:
+		return integer(int64(val.(Uint64Value).Get()));
+	case Float32Kind:
+		return "float32";
+	case Float64Kind:
+		return "float64";
+	case Float80Kind:
+		return "float80";
+	case StringKind:
+		return val.(StringValue).Get();
+	case PtrKind:
+		p := typ.(PtrType);
+		return ValueToString(p.Sub());
+	default:
+		panicln("reflect.ValueToString: can't print type ", val.Kind());
+	}
+	return "reflect.ValueToString: can't happen";
 }
diff --git a/usr/r/reflect/type.go b/usr/r/reflect/type.go
index 965a3177b3..9ed6c75e9e 100644
--- a/usr/r/reflect/type.go
+++ b/usr/r/reflect/type.go
@@ -36,45 +36,58 @@ export const (
 	Uint8Kind;
 )
 
+var ptrsize int
+var interfacesize int
+
 var MissingString = "missing"	// syntactic name for undefined type names
 
-type Type interface {
+export type Type interface {
 	Kind()	int;
+	Size()	int;
 }
 
+// -- Basic
+
 type BasicType struct{
-	kind	int
+	kind	int;
+	size	int;
 }
 
 func (t *BasicType) Kind() int {
 	return t.kind
 }
 
-func NewBasicType(k int) Type {
+func (t *BasicType) Size() int {
+	return t.size
+}
+
+func NewBasicType(k, size int) Type {
 	t := new(BasicType);
 	t.kind = k;
+	t.size = size;
 	return t;
 }
 
-// Basic types
+// Prebuilt basic types
 export var (
-	Missing = NewBasicType(MissingKind);
-	Int8 = NewBasicType(Int8Kind);
-	Int16 = NewBasicType(Int16Kind);
-	Int32 = NewBasicType(Int32Kind);
-	Int64 = NewBasicType(Int64Kind);
-	Uint8 = NewBasicType(Uint8Kind);
-	Uint16 = NewBasicType(Uint16Kind);
-	Uint32 = NewBasicType(Uint32Kind);
-	Uint64 = NewBasicType(Uint64Kind);
-	Float32 = NewBasicType(Float32Kind);
-	Float64 = NewBasicType(Float64Kind);
-	Float80 = NewBasicType(Float80Kind);
-	String = NewBasicType(StringKind);
+	Missing = NewBasicType(MissingKind, 1);
+	Int8 = NewBasicType(Int8Kind, 1);
+	Int16 = NewBasicType(Int16Kind, 2);
+	Int32 = NewBasicType(Int32Kind, 4);
+	Int64 = NewBasicType(Int64Kind, 8);
+	Uint8 = NewBasicType(Uint8Kind, 1);
+	Uint16 = NewBasicType(Uint16Kind, 2);
+	Uint32 = NewBasicType(Uint32Kind, 4);
+	Uint64 = NewBasicType(Uint64Kind, 8);
+	Float32 = NewBasicType(Float32Kind, 4);
+	Float64 = NewBasicType(Float64Kind, 8);
+	Float80 = NewBasicType(Float80Kind, 10);	// TODO: strange size?
+	String = NewBasicType(StringKind, 8);	// implemented as a pointer
 )
 
 // Stub types allow us to defer evaluating type names until needed.
 // If the name is empty, the type must be non-nil.
+
 type StubType struct {
 	name	string;
 	typ		Type;
@@ -99,6 +112,8 @@ func NewNamedStubType(n string) *StubType {
 	return s;
 }
 
+// -- Pointer
+
 export type PtrType interface {
 	Sub()	Type
 }
@@ -111,6 +126,10 @@ func (t *PtrTypeStruct) Kind() int {
 	return PtrKind
 }
 
+func (t *PtrTypeStruct) Size() int {
+	return ptrsize
+}
+
 func (t *PtrTypeStruct) Sub() Type {
 	return t.sub.Get()
 }
@@ -121,6 +140,8 @@ func NewPtrTypeStruct(sub *StubType) *PtrTypeStruct {
 	return t;
 }
 
+// -- Array
+
 export type ArrayType interface {
 	Len()	int;
 	Elem()	Type;
@@ -135,6 +156,13 @@ func (t *ArrayTypeStruct) Kind() int {
 	return ArrayKind
 }
 
+func (t *ArrayTypeStruct) Size() int {
+	if t.len < 0 {
+		return ptrsize	// open arrays are pointers to structures
+	}
+	return t.len * t.elem.Get().Size();
+}
+
 func (t *ArrayTypeStruct) Len() int {
 	// -1 is open array?  TODO
 	return t.len
@@ -151,6 +179,8 @@ func NewArrayTypeStruct(len int, elem *StubType) *ArrayTypeStruct {
 	return t;
 }
 
+// -- Map
+
 export type MapType interface {
 	Key()	Type;
 	Elem()	Type;
@@ -165,6 +195,11 @@ func (t *MapTypeStruct) Kind() int {
 	return MapKind
 }
 
+func (t *MapTypeStruct) Size() int {
+	panic("reflect.type: map.Size(): cannot happen");
+	return 0
+}
+
 func (t *MapTypeStruct) Key() Type {
 	return t.key.Get()
 }
@@ -180,6 +215,8 @@ func NewMapTypeStruct(key, elem *StubType) *MapTypeStruct {
 	return t;
 }
 
+// -- Chan
+
 export type ChanType interface {
 	Dir()	int;
 	Elem()	Type;
@@ -199,6 +236,11 @@ type ChanTypeStruct struct {
 func (t *ChanTypeStruct) Kind() int {
 	return ChanKind
 }
+	
+func (t *ChanTypeStruct) Size() int {
+	panic("reflect.type: chan.Size(): cannot happen");
+	return 0
+}
 
 func (t *ChanTypeStruct) Dir() int {
 	// -1 is open array?  TODO
@@ -216,6 +258,8 @@ func NewChanTypeStruct(dir int, elem *StubType) *ChanTypeStruct {
 	return t;
 }
 
+// -- Struct
+
 export type StructType interface {
 	Field(int)	(name string, typ Type);
 	Len()	int;
@@ -224,6 +268,7 @@ export type StructType interface {
 type Field struct {
 	name	string;
 	typ	*StubType;
+	size	int;
 }
 
 type StructTypeStruct struct {
@@ -234,6 +279,25 @@ func (t *StructTypeStruct) Kind() int {
 	return StructKind
 }
 
+// TODO: not portable; depends on 6g
+func (t *StructTypeStruct) Size() int {
+	size := 0;
+	for i := 0; i < len(t.field); i++ {
+		elemsize := t.field[i].typ.Get().Size();
+		// pad until at (elemsize mod 8) boundary
+		align := elemsize - 1;
+		if align > 7 {	// BUG: we know structs are at 8-aligned
+			align = 7
+		}
+		if align > 0 {
+			size = (size + align) & ^align;
+		}
+		size += elemsize;
+	}
+	size = (size + 7) & ^7;
+	return size;
+}
+
 func (t *StructTypeStruct) Field(i int) (name string, typ Type) {
 	return t.field[i].name, t.field[i].typ.Get()
 }
@@ -248,6 +312,8 @@ func NewStructTypeStruct(field *[]Field) *StructTypeStruct {
 	return t;
 }
 
+// -- Interface
+
 export type InterfaceType interface {
 	Field(int)	(name string, typ Type);
 	Len()	int;
@@ -275,6 +341,12 @@ func (t *InterfaceTypeStruct) Kind() int {
 	return InterfaceKind
 }
 
+func (t *InterfaceTypeStruct) Size() int {
+	return interfacesize
+}
+
+// -- Func
+
 export type FuncType interface {
 	In()	StructType;
 	Out()	StructType;
@@ -289,6 +361,11 @@ func (t *FuncTypeStruct) Kind() int {
 	return FuncKind
 }
 
+func (t *FuncTypeStruct) Size() int {
+	panic("reflect.type: func.Size(): cannot happen");
+	return 0
+}
+
 func (t *FuncTypeStruct) In() StructType {
 	return t.in
 }
@@ -330,6 +407,9 @@ func Unlock() {
 }
 
 func init() {
+	ptrsize = 8;	// TODO: compute this
+	interfacesize = 2*ptrsize;	// TODO: compute this
+
 	lockchan = new(chan bool, 1);	// unlocked at creation - buffer is empty
 	Lock();	// not necessary because of init ordering but be safe.
 
-- 
2.30.9