Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 1 | // $G $D/$F.go && $L $F.$A && ./$A.out |
| 2 | |
| 3 | // Copyright 2009 The Go Authors. All rights reserved. |
| 4 | // Use of this source code is governed by a BSD-style |
| 5 | // license that can be found in the LICENSE file. |
| 6 | |
| 7 | // Test close(c), closed(c). |
| 8 | // |
| 9 | // TODO(rsc): Doesn't check behavior of close(c) when there |
| 10 | // are blocked senders/receivers. |
| 11 | |
| 12 | package main |
| 13 | |
| 14 | type Chan interface { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 15 | Send(int) |
| 16 | Nbsend(int) bool |
| 17 | Recv() int |
| 18 | Nbrecv() (int, bool) |
| 19 | Close() |
| 20 | Closed() bool |
| 21 | Impl() string |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 22 | } |
| 23 | |
| 24 | // direct channel operations |
| 25 | type XChan chan int |
| 26 | func (c XChan) Send(x int) { |
| 27 | c <- x |
| 28 | } |
| 29 | |
| 30 | func (c XChan) Nbsend(x int) bool { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 31 | return c <- x |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 32 | } |
| 33 | |
| 34 | func (c XChan) Recv() int { |
| 35 | return <-c |
| 36 | } |
| 37 | |
| 38 | func (c XChan) Nbrecv() (int, bool) { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 39 | x, ok := <-c |
| 40 | return x, ok |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 41 | } |
| 42 | |
| 43 | func (c XChan) Close() { |
| 44 | close(c) |
| 45 | } |
| 46 | |
| 47 | func (c XChan) Closed() bool { |
| 48 | return closed(c) |
| 49 | } |
| 50 | |
| 51 | func (c XChan) Impl() string { |
| 52 | return "(<- operator)" |
| 53 | } |
| 54 | |
| 55 | // indirect operations via select |
| 56 | type SChan chan int |
| 57 | func (c SChan) Send(x int) { |
| 58 | select { |
| 59 | case c <- x: |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | func (c SChan) Nbsend(x int) bool { |
| 64 | select { |
| 65 | case c <- x: |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 66 | return true |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 67 | default: |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 68 | return false |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 69 | } |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 70 | panic("nbsend") |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | func (c SChan) Recv() int { |
| 74 | select { |
| 75 | case x := <-c: |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 76 | return x |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 77 | } |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 78 | panic("recv") |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | func (c SChan) Nbrecv() (int, bool) { |
| 82 | select { |
| 83 | case x := <-c: |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 84 | return x, true |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 85 | default: |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 86 | return 0, false |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 87 | } |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 88 | panic("nbrecv") |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | func (c SChan) Close() { |
| 92 | close(c) |
| 93 | } |
| 94 | |
| 95 | func (c SChan) Closed() bool { |
| 96 | return closed(c) |
| 97 | } |
| 98 | |
| 99 | func (c SChan) Impl() string { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 100 | return "(select)" |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | func test1(c Chan) { |
| 104 | // not closed until the close signal (a zero value) has been received. |
| 105 | if c.Closed() { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 106 | println("test1: Closed before Recv zero:", c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | for i := 0; i < 3; i++ { |
| 110 | // recv a close signal (a zero value) |
| 111 | if x := c.Recv(); x != 0 { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 112 | println("test1: recv on closed got non-zero:", x, c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | // should now be closed. |
| 116 | if !c.Closed() { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 117 | println("test1: not closed after recv zero", c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | // should work with ,ok: received a value without blocking, so ok == true. |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 121 | x, ok := c.Nbrecv() |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 122 | if !ok { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 123 | println("test1: recv on closed got not ok", c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 124 | } |
| 125 | if x != 0 { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 126 | println("test1: recv ,ok on closed got non-zero:", x, c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 127 | } |
| 128 | } |
| 129 | |
| 130 | // send should work with ,ok too: sent a value without blocking, so ok == true. |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 131 | ok := c.Nbsend(1) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 132 | if !ok { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 133 | println("test1: send on closed got not ok", c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | // but the value should have been discarded. |
| 137 | if x := c.Recv(); x != 0 { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 138 | println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | // similarly Send. |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 142 | c.Send(2) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 143 | if x := c.Recv(); x != 0 { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 144 | println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 145 | } |
| 146 | } |
| 147 | |
| 148 | func testasync1(c Chan) { |
| 149 | // not closed until the close signal (a zero value) has been received. |
| 150 | if c.Closed() { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 151 | println("testasync1: Closed before Recv zero:", c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | // should be able to get the last value via Recv |
| 155 | if x := c.Recv(); x != 1 { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 156 | println("testasync1: Recv did not get 1:", x, c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 157 | } |
| 158 | |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 159 | test1(c) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | func testasync2(c Chan) { |
| 163 | // not closed until the close signal (a zero value) has been received. |
| 164 | if c.Closed() { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 165 | println("testasync2: Closed before Recv zero:", c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | // should be able to get the last value via Nbrecv |
| 169 | if x, ok := c.Nbrecv(); !ok || x != 1 { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 170 | println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl()) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 171 | } |
| 172 | |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 173 | test1(c) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | func closedsync() chan int { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 177 | c := make(chan int) |
| 178 | close(c) |
| 179 | return c |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | func closedasync() chan int { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 183 | c := make(chan int, 2) |
| 184 | c <- 1 |
| 185 | close(c) |
| 186 | return c |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | func main() { |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 190 | test1(XChan(closedsync())) |
| 191 | test1(SChan(closedsync())) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 192 | |
Rob Pike | 4f61fc9 | 2010-09-04 10:36:13 +1000 | [diff] [blame^] | 193 | testasync1(XChan(closedasync())) |
| 194 | testasync1(SChan(closedasync())) |
| 195 | testasync2(XChan(closedasync())) |
| 196 | testasync2(SChan(closedasync())) |
Russ Cox | 13584f4 | 2009-03-23 18:50:35 -0700 | [diff] [blame] | 197 | } |