1
0
mirror of https://github.com/golang/go synced 2024-11-26 01:37:58 -07:00

reflection for channels

R=r
DELTA=188  (171 added, 6 deleted, 11 changed)
OCL=31352
CL=31361
This commit is contained in:
Russ Cox 2009-07-08 15:00:54 -07:00
parent 2ad7958b7e
commit 5ddaf9a098
6 changed files with 183 additions and 18 deletions

View File

@ -598,7 +598,7 @@ func TestNilPtrValueSub(t *testing.T) {
}
}
func TestMapAccess(t *testing.T) {
func TestMap(t *testing.T) {
m := map[string]int{ "a": 1, "b": 2 };
mv := NewValue(m).(*MapValue);
if n := mv.Len(); n != len(m) {
@ -651,3 +651,77 @@ func TestMapAccess(t *testing.T) {
t.Errorf("newm[\"a\"] = %d after delete", v);
}
}
func TestChan(t *testing.T) {
for loop := 0; loop < 2; loop++ {
var c chan int;
var cv *ChanValue;
// check both ways to allocate channels
switch loop {
case 1:
c = make(chan int, 1);
cv = NewValue(c).(*ChanValue);
case 0:
cv = MakeChan(Typeof(c).(*ChanType), 1);
c = cv.Interface().(chan int);
}
// Send
cv.Send(NewValue(2));
if i := <-c; i != 2 {
t.Errorf("reflect Send 2, native recv %d", i);
}
// Recv
c <- 3;
if i := cv.Recv().(*IntValue).Get(); i != 3 {
t.Errorf("native send 3, reflect Recv %d", i);
}
// TryRecv fail
val := cv.TryRecv();
if val != nil {
t.Errorf("TryRecv on empty chan: %s", valueToString(val));
}
// TryRecv success
c <- 4;
val = cv.TryRecv();
if val == nil {
t.Errorf("TryRecv on ready chan got nil");
} else if i := val.(*IntValue).Get(); i != 4 {
t.Errorf("native send 4, TryRecv %d", i);
}
// TrySend fail
c <- 100;
ok := cv.TrySend(NewValue(5));
i := <-c;
if ok {
t.Errorf("TrySend on full chan succeeded: value %d", i);
}
// TrySend success
ok = cv.TrySend(NewValue(6));
if !ok {
t.Errorf("TrySend on empty chan failed");
} else {
if i = <-c; i != 6 {
t.Errorf("TrySend 6, recv %d", i);
}
}
}
// check creation of unbuffered channel
var c chan int;
cv := MakeChan(Typeof(c).(*ChanType), 0);
c = cv.Interface().(chan int);
if cv.TrySend(NewValue(7)) {
t.Errorf("TrySend on sync chan succeeded");
}
if cv.TryRecv() != nil {
t.Errorf("TryRecv on sync chan succeeded");
}
}

View File

@ -631,26 +631,74 @@ func (v *ChanValue) Get() uintptr {
return *(*uintptr)(v.addr);
}
// implemented in ../pkg/runtime/reflect.cgo
func makechan(typ *runtime.ChanType, size uint32) (ch *byte)
func chansend(ch, val *byte, pres *bool)
func chanrecv(ch, val *byte, pres *bool)
// internal send; non-blocking if b != nil
func (v *ChanValue) send(x Value, b *bool) {
t := v.Type().(*ChanType);
if t.Dir() & SendDir == 0{
panic("send on recv-only channel");
}
ch := *(**byte)(v.addr);
chansend(ch, (*byte)(x.getAddr()), b);
}
// internal recv; non-blocking if b != nil
func (v *ChanValue) recv(b *bool) Value {
t := v.Type().(*ChanType);
if t.Dir() & RecvDir == 0 {
panic("recv on send-only channel");
}
ch := *(**byte)(v.addr);
newval := MakeZero(t.Elem());
x := MakeZero(t.Elem());
chanrecv(ch, (*byte)(x.getAddr()), b);
return x;
}
// Send sends x on the channel v.
func (v *ChanValue) Send(x Value) {
panic("unimplemented: channel Send");
v.send(x, nil);
}
// Recv receives and returns a value from the channel v.
func (v *ChanValue) Recv() Value {
panic("unimplemented: channel Receive");
return v.recv(nil);
}
// TrySend attempts to sends x on the channel v but will not block.
// It returns true if the value was sent, false otherwise.
func (v *ChanValue) TrySend(x Value) bool {
panic("unimplemented: channel TrySend");
var ok bool;
v.send(x, &ok);
return ok;
}
// TryRecv attempts to receive a value from the channel v but will not block.
// It returns the value if one is received, nil otherwise.
func (v *ChanValue) TryRecv() Value {
panic("unimplemented: channel TryRecv");
var ok bool;
x := v.recv(&ok);
if !ok {
return nil;
}
return x;
}
// MakeChan creates a new channel with the specified type and buffer size.
func MakeChan(typ *ChanType, buffer int) *ChanValue {
if buffer < 0 {
panic("MakeChan: negative buffer size");
}
if typ.Dir() != BothDir {
panic("MakeChan: unidirectional channel type");
}
v := MakeZero(typ).(*ChanValue);
*(**byte)(v.addr) = makechan((*runtime.ChanType)(unsafe.Pointer(typ)), uint32(buffer));
return v;
}
/*
@ -818,6 +866,7 @@ func (v *MapValue) Keys() []Value {
return a[0:i];
}
// MakeMap creates a new map of the specified type.
func MakeMap(typ *MapType) *MapValue {
v := MakeZero(typ).(*MapValue);
*(**byte)(v.addr) = makemap((*runtime.MapType)(unsafe.Pointer(typ)));

View File

@ -15,7 +15,6 @@ enum
Emax = 0x0800, // error limit before throw
};
typedef struct Hchan Hchan;
typedef struct Link Link;
typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG;
@ -88,10 +87,8 @@ static uint32 gcd(uint32, uint32);
static uint32 fastrand1(void);
static uint32 fastrand2(void);
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
void
sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
Hchan* ret)
Hchan*
makechan(uint32 elemsize, uint32 elemalg, uint32 hint)
{
Hchan *c;
int32 i;
@ -126,9 +123,6 @@ sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
c->dataqsiz = hint;
}
ret = c;
FLUSH(&ret);
if(debug) {
prints("newchan: chan=");
sys·printpointer(c);
@ -140,6 +134,16 @@ sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
sys·printint(c->dataqsiz);
prints("\n");
}
return c;
}
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
void
sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint, Hchan *ret)
{
ret = makechan(elemsize, elemalg, hint);
FLUSH(&ret);
}
static void
@ -162,7 +166,7 @@ incerr(Hchan* c)
* not complete
*/
void
sendchan(Hchan *c, byte *ep, bool *pres)
chansend(Hchan *c, byte *ep, bool *pres)
{
SudoG *sg;
G* gp;
@ -266,7 +270,7 @@ closed:
unlock(&chanlock);
}
static void
void
chanrecv(Hchan* c, byte *ep, bool* pres)
{
SudoG *sg;
@ -381,7 +385,7 @@ sys·chansend1(Hchan* c, ...)
o = rnd(sizeof(c), c->elemsize);
ae = (byte*)&c + o;
sendchan(c, ae, nil);
chansend(c, ae, nil);
}
// chansend2(hchan *chan any, elem any) (pres bool);
@ -396,7 +400,7 @@ sys·chansend2(Hchan* c, ...)
o = rnd(o+c->elemsize, Structrnd);
ap = (byte*)&c + o;
sendchan(c, ae, ap);
chansend(c, ae, ap);
}
// chanrecv1(hchan *chan any) (elem any);

View File

@ -49,3 +49,27 @@ func makemap(typ *byte) (map *byte) {
map = (byte*)makemap(t->key->size, t->elem->size, t->key->alg, t->elem->alg, 0);
}
/*
* Go wrappers around the C functions in chan.c
*/
func makechan(typ *byte, size uint32) (ch *byte) {
ChanType *t;
// typ is a *runtime.ChanType, but the ChanType
// defined in type.h includes an interface value header
// in front of the raw ChanType. the -2 below backs up
// to the interface value header.
t = (ChanType*)((void**)typ - 2);
ch = (byte*)makechan(t->elem->size, t->elem->alg, size);
}
func chansend(ch *byte, val *byte, pres *bool) {
chansend((Hchan*)ch, val, pres);
}
func chanrecv(ch *byte, val *byte, pres *bool) {
chanrecv((Hchan*)ch, val, pres);
}

View File

@ -61,6 +61,7 @@ typedef struct Eface Eface;
typedef struct Type Type;
typedef struct Defer Defer;
typedef struct hash Hmap;
typedef struct Hchan Hchan;
/*
* per cpu declaration
@ -458,6 +459,7 @@ float64 ldexp(float64 d, int32 e);
float64 modf(float64 d, float64 *ip);
void semacquire(uint32*);
void semrelease(uint32*);
void mapassign(Hmap*, byte*, byte*);
void mapaccess(Hmap*, byte*, byte*, bool*);
struct hash_iter* mapiterinit(Hmap*);
@ -465,3 +467,7 @@ void mapiternext(struct hash_iter*);
bool mapiterkey(struct hash_iter*, void*);
void mapiterkeyvalue(struct hash_iter*, void*, void*);
Hmap* makemap(uint32, uint32, uint32, uint32, uint32);
Hchan* makechan(uint32, uint32, uint32);
void chansend(Hchan*, void*, bool*);
void chanrecv(Hchan*, void*, bool*);

View File

@ -12,6 +12,7 @@ typedef struct InterfaceType InterfaceType;
typedef struct Method Method;
typedef struct IMethod IMethod;
typedef struct MapType MapType;
typedef struct ChanType ChanType;
struct CommonType
{
@ -71,3 +72,10 @@ struct MapType
Type *key;
Type *elem;
};
struct ChanType
{
Type;
Type *elem;
uintptr dir;
};