mirror of
https://github.com/golang/go
synced 2024-11-11 19:51:37 -07:00
add test for close/closed, fix a few implementation bugs.
R=ken OCL=26664 CL=26664
This commit is contained in:
parent
86145611b0
commit
13584f4a23
@ -176,13 +176,13 @@ sendchan(Hchan *c, byte *ep, bool *pres)
|
||||
}
|
||||
|
||||
lock(&chanlock);
|
||||
loop:
|
||||
if(c->closed & Wclosed)
|
||||
goto closed;
|
||||
|
||||
if(c->dataqsiz > 0)
|
||||
goto asynch;
|
||||
|
||||
if(c->closed & Wclosed)
|
||||
goto closed;
|
||||
|
||||
sg = dequeue(&c->recvq, c);
|
||||
if(sg != nil) {
|
||||
if(ep != nil)
|
||||
@ -215,6 +215,8 @@ sendchan(Hchan *c, byte *ep, bool *pres)
|
||||
|
||||
lock(&chanlock);
|
||||
sg = g->param;
|
||||
if(sg == nil)
|
||||
goto loop;
|
||||
freesg(c, sg);
|
||||
unlock(&chanlock);
|
||||
if(pres != nil)
|
||||
@ -260,7 +262,7 @@ asynch:
|
||||
closed:
|
||||
incerr(c);
|
||||
if(pres != nil)
|
||||
*pres = false;
|
||||
*pres = true;
|
||||
unlock(&chanlock);
|
||||
}
|
||||
|
||||
@ -277,6 +279,7 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
|
||||
}
|
||||
|
||||
lock(&chanlock);
|
||||
loop:
|
||||
if(c->dataqsiz > 0)
|
||||
goto asynch;
|
||||
|
||||
@ -312,11 +315,8 @@ chanrecv(Hchan* c, byte *ep, bool* pres)
|
||||
|
||||
lock(&chanlock);
|
||||
sg = g->param;
|
||||
|
||||
if(c->closed & Wclosed) {
|
||||
freesg(c, sg);
|
||||
goto closed;
|
||||
}
|
||||
if(sg == nil)
|
||||
goto loop;
|
||||
|
||||
c->elemalg->copy(c->elemsize, ep, sg->elem);
|
||||
freesg(c, sg);
|
||||
@ -368,7 +368,7 @@ closed:
|
||||
c->closed |= Rclosed;
|
||||
incerr(c);
|
||||
if(pres != nil)
|
||||
*pres = false;
|
||||
*pres = true;
|
||||
unlock(&chanlock);
|
||||
}
|
||||
|
||||
@ -651,32 +651,32 @@ loop:
|
||||
c = cas->chan;
|
||||
if(c->dataqsiz > 0) {
|
||||
if(cas->send) {
|
||||
if(c->closed & Wclosed)
|
||||
goto sclose;
|
||||
if(c->qcount < c->dataqsiz)
|
||||
goto asyns;
|
||||
if(c->closed & Wclosed)
|
||||
goto gots;
|
||||
goto next1;
|
||||
}
|
||||
if(c->qcount > 0)
|
||||
goto asynr;
|
||||
if(c->closed & Wclosed)
|
||||
goto gotr;
|
||||
goto rclose;
|
||||
goto next1;
|
||||
}
|
||||
|
||||
if(cas->send) {
|
||||
if(c->closed & Wclosed)
|
||||
goto sclose;
|
||||
sg = dequeue(&c->recvq, c);
|
||||
if(sg != nil)
|
||||
goto gots;
|
||||
if(c->closed & Wclosed)
|
||||
goto gots;
|
||||
goto next1;
|
||||
}
|
||||
sg = dequeue(&c->sendq, c);
|
||||
if(sg != nil)
|
||||
goto gotr;
|
||||
if(c->closed & Wclosed)
|
||||
goto gotr;
|
||||
goto rclose;
|
||||
|
||||
next1:
|
||||
o += p;
|
||||
@ -823,13 +823,6 @@ gotr:
|
||||
sys·printint(o);
|
||||
prints("\n");
|
||||
}
|
||||
if(c->closed & Wclosed) {
|
||||
if(cas->u.elemp != nil)
|
||||
c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
|
||||
c->closed |= Rclosed;
|
||||
incerr(c);
|
||||
goto retc;
|
||||
}
|
||||
if(cas->u.elemp != nil)
|
||||
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
|
||||
gp = sg->g;
|
||||
@ -837,6 +830,13 @@ gotr:
|
||||
ready(gp);
|
||||
goto retc;
|
||||
|
||||
rclose:
|
||||
if(cas->u.elemp != nil)
|
||||
c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
|
||||
c->closed |= Rclosed;
|
||||
incerr(c);
|
||||
goto retc;
|
||||
|
||||
gots:
|
||||
// send path to wakeup the receiver (sg)
|
||||
if(debug) {
|
||||
@ -848,14 +848,17 @@ gots:
|
||||
sys·printint(o);
|
||||
prints("\n");
|
||||
}
|
||||
if(c->closed & Wclosed) {
|
||||
incerr(c);
|
||||
goto retc;
|
||||
}
|
||||
if(c->closed & Wclosed)
|
||||
goto sclose;
|
||||
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
|
||||
gp = sg->g;
|
||||
gp->param = sg;
|
||||
ready(gp);
|
||||
goto retc;
|
||||
|
||||
sclose:
|
||||
incerr(c);
|
||||
goto retc;
|
||||
|
||||
retc:
|
||||
if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
|
||||
@ -909,7 +912,6 @@ sys·closechan(Hchan *c)
|
||||
void
|
||||
sys·closedchan(Hchan *c, bool closed)
|
||||
{
|
||||
|
||||
// test Rclosed
|
||||
closed = 0;
|
||||
if(c->closed & Rclosed)
|
||||
|
197
test/closedchan.go
Normal file
197
test/closedchan.go
Normal file
@ -0,0 +1,197 @@
|
||||
// $G $D/$F.go && $L $F.$A && ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
// Test close(c), closed(c).
|
||||
//
|
||||
// TODO(rsc): Doesn't check behavior of close(c) when there
|
||||
// are blocked senders/receivers.
|
||||
|
||||
package main
|
||||
|
||||
type Chan interface {
|
||||
Send(int);
|
||||
Nbsend(int) bool;
|
||||
Recv() int;
|
||||
Nbrecv() (int, bool);
|
||||
Close();
|
||||
Closed() bool;
|
||||
Impl() string;
|
||||
}
|
||||
|
||||
// direct channel operations
|
||||
type XChan chan int
|
||||
func (c XChan) Send(x int) {
|
||||
c <- x
|
||||
}
|
||||
|
||||
func (c XChan) Nbsend(x int) bool {
|
||||
return c <- x;
|
||||
}
|
||||
|
||||
func (c XChan) Recv() int {
|
||||
return <-c
|
||||
}
|
||||
|
||||
func (c XChan) Nbrecv() (int, bool) {
|
||||
x, ok := <-c;
|
||||
return x, ok;
|
||||
}
|
||||
|
||||
func (c XChan) Close() {
|
||||
close(c)
|
||||
}
|
||||
|
||||
func (c XChan) Closed() bool {
|
||||
return closed(c)
|
||||
}
|
||||
|
||||
func (c XChan) Impl() string {
|
||||
return "(<- operator)"
|
||||
}
|
||||
|
||||
// indirect operations via select
|
||||
type SChan chan int
|
||||
func (c SChan) Send(x int) {
|
||||
select {
|
||||
case c <- x:
|
||||
}
|
||||
}
|
||||
|
||||
func (c SChan) Nbsend(x int) bool {
|
||||
select {
|
||||
case c <- x:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
panic("nbsend");
|
||||
}
|
||||
|
||||
func (c SChan) Recv() int {
|
||||
select {
|
||||
case x := <-c:
|
||||
return x;
|
||||
}
|
||||
panic("recv");
|
||||
}
|
||||
|
||||
func (c SChan) Nbrecv() (int, bool) {
|
||||
select {
|
||||
case x := <-c:
|
||||
return x, true;
|
||||
default:
|
||||
return 0, false;
|
||||
}
|
||||
panic("nbrecv");
|
||||
}
|
||||
|
||||
func (c SChan) Close() {
|
||||
close(c)
|
||||
}
|
||||
|
||||
func (c SChan) Closed() bool {
|
||||
return closed(c)
|
||||
}
|
||||
|
||||
func (c SChan) Impl() string {
|
||||
return "(select)";
|
||||
}
|
||||
|
||||
func test1(c Chan) {
|
||||
// not closed until the close signal (a zero value) has been received.
|
||||
if c.Closed() {
|
||||
println("test1: Closed before Recv zero:", c.Impl());
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
// recv a close signal (a zero value)
|
||||
if x := c.Recv(); x != 0 {
|
||||
println("test1: recv on closed got non-zero:", x, c.Impl());
|
||||
}
|
||||
|
||||
// should now be closed.
|
||||
if !c.Closed() {
|
||||
println("test1: not closed after recv zero", c.Impl());
|
||||
}
|
||||
|
||||
// should work with ,ok: received a value without blocking, so ok == true.
|
||||
x, ok := c.Nbrecv();
|
||||
if !ok {
|
||||
println("test1: recv on closed got not ok", c.Impl());
|
||||
}
|
||||
if x != 0 {
|
||||
println("test1: recv ,ok on closed got non-zero:", x, c.Impl());
|
||||
}
|
||||
}
|
||||
|
||||
// send should work with ,ok too: sent a value without blocking, so ok == true.
|
||||
ok := c.Nbsend(1);
|
||||
if !ok {
|
||||
println("test1: send on closed got not ok", c.Impl());
|
||||
}
|
||||
|
||||
// but the value should have been discarded.
|
||||
if x := c.Recv(); x != 0 {
|
||||
println("test1: recv on closed got non-zero after send on closed:", x, c.Impl());
|
||||
}
|
||||
|
||||
// similarly Send.
|
||||
c.Send(2);
|
||||
if x := c.Recv(); x != 0 {
|
||||
println("test1: recv on closed got non-zero after send on closed:", x, c.Impl());
|
||||
}
|
||||
}
|
||||
|
||||
func testasync1(c Chan) {
|
||||
// not closed until the close signal (a zero value) has been received.
|
||||
if c.Closed() {
|
||||
println("testasync1: Closed before Recv zero:", c.Impl());
|
||||
}
|
||||
|
||||
// should be able to get the last value via Recv
|
||||
if x := c.Recv(); x != 1 {
|
||||
println("testasync1: Recv did not get 1:", x, c.Impl());
|
||||
}
|
||||
|
||||
test1(c);
|
||||
}
|
||||
|
||||
func testasync2(c Chan) {
|
||||
// not closed until the close signal (a zero value) has been received.
|
||||
if c.Closed() {
|
||||
println("testasync2: Closed before Recv zero:", c.Impl());
|
||||
}
|
||||
|
||||
// should be able to get the last value via Nbrecv
|
||||
if x, ok := c.Nbrecv(); !ok || x != 1 {
|
||||
println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl());
|
||||
}
|
||||
|
||||
test1(c);
|
||||
}
|
||||
|
||||
func closedsync() chan int {
|
||||
c := make(chan int);
|
||||
close(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
func closedasync() chan int {
|
||||
c := make(chan int, 2);
|
||||
c <- 1;
|
||||
close(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
func main() {
|
||||
test1(XChan(closedsync()));
|
||||
test1(SChan(closedsync()));
|
||||
|
||||
testasync1(XChan(closedasync()));
|
||||
testasync1(SChan(closedasync()));
|
||||
testasync2(XChan(closedasync()));
|
||||
testasync2(SChan(closedasync()));
|
||||
}
|
Loading…
Reference in New Issue
Block a user