blob: 0dbe662d84f985b6821c5d5260bd988a5dbbceec [file] [log] [blame]
Russ Cox13584f42009-03-23 18:50:35 -07001// $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
Russ Cox3f915f52011-03-11 14:47:44 -05007// Test close(c), receive of closed channel.
Russ Cox13584f42009-03-23 18:50:35 -07008//
9// TODO(rsc): Doesn't check behavior of close(c) when there
10// are blocked senders/receivers.
11
12package main
13
14type Chan interface {
Rob Pike4f61fc92010-09-04 10:36:13 +100015 Send(int)
16 Nbsend(int) bool
Russ Cox3f915f52011-03-11 14:47:44 -050017 Recv() (int)
Rob Pike4f61fc92010-09-04 10:36:13 +100018 Nbrecv() (int, bool)
Russ Cox3f915f52011-03-11 14:47:44 -050019 Recv2() (int, bool)
20 Nbrecv2() (int, bool, bool)
Rob Pike4f61fc92010-09-04 10:36:13 +100021 Close()
Rob Pike4f61fc92010-09-04 10:36:13 +100022 Impl() string
Russ Cox13584f42009-03-23 18:50:35 -070023}
24
Russ Coxf4e76d82011-01-31 18:36:28 -050025// direct channel operations when possible
Russ Cox13584f42009-03-23 18:50:35 -070026type XChan chan int
Russ Coxf4e76d82011-01-31 18:36:28 -050027
Russ Cox13584f42009-03-23 18:50:35 -070028func (c XChan) Send(x int) {
29 c <- x
30}
31
32func (c XChan) Nbsend(x int) bool {
Russ Coxf4e76d82011-01-31 18:36:28 -050033 select {
34 case c <- x:
35 return true
36 default:
37 return false
38 }
39 panic("nbsend")
Russ Cox13584f42009-03-23 18:50:35 -070040}
41
42func (c XChan) Recv() int {
43 return <-c
44}
45
46func (c XChan) Nbrecv() (int, bool) {
Russ Coxf4e76d82011-01-31 18:36:28 -050047 select {
48 case x := <-c:
49 return x, true
50 default:
51 return 0, false
52 }
53 panic("nbrecv")
Russ Cox13584f42009-03-23 18:50:35 -070054}
55
Russ Cox3f915f52011-03-11 14:47:44 -050056func (c XChan) Recv2() (int, bool) {
57 x, ok := <-c
58 return x, ok
Russ Cox13584f42009-03-23 18:50:35 -070059}
60
Russ Cox3f915f52011-03-11 14:47:44 -050061func (c XChan) Nbrecv2() (int, bool, bool) {
62 select {
63 case x, ok := <-c:
64 return x, ok, true
65 default:
66 return 0, false, false
67 }
68 panic("nbrecv2")
69}
70
71func (c XChan) Close() {
72 close(c)
Russ Cox13584f42009-03-23 18:50:35 -070073}
74
75func (c XChan) Impl() string {
76 return "(<- operator)"
77}
78
79// indirect operations via select
80type SChan chan int
Russ Coxf4e76d82011-01-31 18:36:28 -050081
Russ Cox13584f42009-03-23 18:50:35 -070082func (c SChan) Send(x int) {
83 select {
84 case c <- x:
85 }
86}
87
88func (c SChan) Nbsend(x int) bool {
89 select {
Russ Cox13584f42009-03-23 18:50:35 -070090 default:
Rob Pike4f61fc92010-09-04 10:36:13 +100091 return false
Russ Coxf4e76d82011-01-31 18:36:28 -050092 case c <- x:
93 return true
Russ Cox13584f42009-03-23 18:50:35 -070094 }
Rob Pike4f61fc92010-09-04 10:36:13 +100095 panic("nbsend")
Russ Cox13584f42009-03-23 18:50:35 -070096}
97
98func (c SChan) Recv() int {
99 select {
100 case x := <-c:
Rob Pike4f61fc92010-09-04 10:36:13 +1000101 return x
Russ Cox13584f42009-03-23 18:50:35 -0700102 }
Rob Pike4f61fc92010-09-04 10:36:13 +1000103 panic("recv")
Russ Cox13584f42009-03-23 18:50:35 -0700104}
105
106func (c SChan) Nbrecv() (int, bool) {
107 select {
Russ Cox13584f42009-03-23 18:50:35 -0700108 default:
Rob Pike4f61fc92010-09-04 10:36:13 +1000109 return 0, false
Russ Coxf4e76d82011-01-31 18:36:28 -0500110 case x := <-c:
111 return x, true
Russ Cox13584f42009-03-23 18:50:35 -0700112 }
Rob Pike4f61fc92010-09-04 10:36:13 +1000113 panic("nbrecv")
Russ Cox13584f42009-03-23 18:50:35 -0700114}
115
Russ Cox3f915f52011-03-11 14:47:44 -0500116func (c SChan) Recv2() (int, bool) {
117 select {
118 case x, ok := <-c:
119 return x, ok
120 }
121 panic("recv")
Russ Cox13584f42009-03-23 18:50:35 -0700122}
123
Russ Cox3f915f52011-03-11 14:47:44 -0500124func (c SChan) Nbrecv2() (int, bool, bool) {
125 select {
126 default:
127 return 0, false, false
128 case x, ok := <-c:
129 return x, ok, true
130 }
131 panic("nbrecv")
132}
133
134func (c SChan) Close() {
135 close(c)
Russ Cox13584f42009-03-23 18:50:35 -0700136}
137
138func (c SChan) Impl() string {
Rob Pike4f61fc92010-09-04 10:36:13 +1000139 return "(select)"
Russ Cox13584f42009-03-23 18:50:35 -0700140}
141
Russ Coxf4e76d82011-01-31 18:36:28 -0500142// indirect operations via larger selects
143var dummy = make(chan bool)
144
145type SSChan chan int
146
147func (c SSChan) Send(x int) {
148 select {
149 case c <- x:
150 case <-dummy:
151 }
152}
153
154func (c SSChan) Nbsend(x int) bool {
155 select {
156 default:
157 return false
158 case <-dummy:
159 case c <- x:
160 return true
161 }
162 panic("nbsend")
163}
164
165func (c SSChan) Recv() int {
166 select {
167 case <-dummy:
168 case x := <-c:
169 return x
170 }
171 panic("recv")
172}
173
174func (c SSChan) Nbrecv() (int, bool) {
175 select {
176 case <-dummy:
177 default:
178 return 0, false
179 case x := <-c:
180 return x, true
181 }
182 panic("nbrecv")
183}
184
Russ Cox3f915f52011-03-11 14:47:44 -0500185func (c SSChan) Recv2() (int, bool) {
186 select {
187 case <-dummy:
188 case x, ok := <-c:
189 return x, ok
190 }
191 panic("recv")
Russ Coxf4e76d82011-01-31 18:36:28 -0500192}
193
Russ Cox3f915f52011-03-11 14:47:44 -0500194func (c SSChan) Nbrecv2() (int, bool, bool) {
195 select {
196 case <-dummy:
197 default:
198 return 0, false, false
199 case x, ok := <-c:
200 return x, ok, true
201 }
202 panic("nbrecv")
203}
204
205func (c SSChan) Close() {
206 close(c)
Russ Coxf4e76d82011-01-31 18:36:28 -0500207}
208
209func (c SSChan) Impl() string {
210 return "(select)"
211}
212
213
Russ Cox27c74d32011-01-21 15:07:13 -0500214func shouldPanic(f func()) {
215 defer func() {
216 if recover() == nil {
217 panic("did not panic")
218 }
219 }()
220 f()
221}
222
Russ Cox13584f42009-03-23 18:50:35 -0700223func test1(c Chan) {
Russ Cox13584f42009-03-23 18:50:35 -0700224 for i := 0; i < 3; i++ {
225 // recv a close signal (a zero value)
226 if x := c.Recv(); x != 0 {
Russ Cox3f915f52011-03-11 14:47:44 -0500227 println("test1: recv on closed:", x, c.Impl())
228 }
229 if x, ok := c.Recv2(); x != 0 || ok {
230 println("test1: recv2 on closed:", x, ok, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700231 }
232
Russ Cox3f915f52011-03-11 14:47:44 -0500233 // should work with select: received a value without blocking, so selected == true.
234 x, selected := c.Nbrecv()
235 if x != 0 || !selected {
236 println("test1: recv on closed nb:", x, selected, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700237 }
Russ Cox3f915f52011-03-11 14:47:44 -0500238 x, ok, selected := c.Nbrecv2()
239 if x != 0 || ok || !selected {
240 println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700241 }
242 }
243
244 // send should work with ,ok too: sent a value without blocking, so ok == true.
Russ Coxf4e76d82011-01-31 18:36:28 -0500245 shouldPanic(func() { c.Nbsend(1) })
Russ Cox13584f42009-03-23 18:50:35 -0700246
Russ Cox27c74d32011-01-21 15:07:13 -0500247 // the value should have been discarded.
Russ Cox13584f42009-03-23 18:50:35 -0700248 if x := c.Recv(); x != 0 {
Rob Pike4f61fc92010-09-04 10:36:13 +1000249 println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700250 }
251
252 // similarly Send.
Russ Coxf4e76d82011-01-31 18:36:28 -0500253 shouldPanic(func() { c.Send(2) })
Russ Cox13584f42009-03-23 18:50:35 -0700254 if x := c.Recv(); x != 0 {
Rob Pike4f61fc92010-09-04 10:36:13 +1000255 println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700256 }
257}
258
259func testasync1(c Chan) {
Russ Cox13584f42009-03-23 18:50:35 -0700260 // should be able to get the last value via Recv
261 if x := c.Recv(); x != 1 {
Rob Pike4f61fc92010-09-04 10:36:13 +1000262 println("testasync1: Recv did not get 1:", x, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700263 }
264
Rob Pike4f61fc92010-09-04 10:36:13 +1000265 test1(c)
Russ Cox13584f42009-03-23 18:50:35 -0700266}
267
268func testasync2(c Chan) {
Russ Cox3f915f52011-03-11 14:47:44 -0500269 // should be able to get the last value via Recv2
270 if x, ok := c.Recv2(); x != 1 || !ok {
271 println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700272 }
273
Russ Cox3f915f52011-03-11 14:47:44 -0500274 test1(c)
275}
276
277func testasync3(c Chan) {
Russ Cox13584f42009-03-23 18:50:35 -0700278 // should be able to get the last value via Nbrecv
Russ Cox3f915f52011-03-11 14:47:44 -0500279 if x, selected := c.Nbrecv(); x != 1 || !selected {
280 println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
Russ Cox13584f42009-03-23 18:50:35 -0700281 }
282
Rob Pike4f61fc92010-09-04 10:36:13 +1000283 test1(c)
Russ Cox13584f42009-03-23 18:50:35 -0700284}
285
Russ Cox3f915f52011-03-11 14:47:44 -0500286func testasync4(c Chan) {
287 // should be able to get the last value via Nbrecv2
288 if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
289 println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
290 }
291 test1(c)
292}
293
Russ Cox13584f42009-03-23 18:50:35 -0700294func closedsync() chan int {
Rob Pike4f61fc92010-09-04 10:36:13 +1000295 c := make(chan int)
296 close(c)
297 return c
Russ Cox13584f42009-03-23 18:50:35 -0700298}
299
300func closedasync() chan int {
Rob Pike4f61fc92010-09-04 10:36:13 +1000301 c := make(chan int, 2)
302 c <- 1
303 close(c)
304 return c
Russ Cox13584f42009-03-23 18:50:35 -0700305}
306
Russ Cox3f915f52011-03-11 14:47:44 -0500307var mks = []func(chan int) Chan {
308 func(c chan int) Chan { return XChan(c) },
309 func(c chan int) Chan { return SChan(c) },
310 func(c chan int) Chan { return SSChan(c) },
311}
Russ Cox13584f42009-03-23 18:50:35 -0700312
Russ Cox3f915f52011-03-11 14:47:44 -0500313var testcloseds = []func(Chan) {
314 testasync1,
315 testasync2,
316 testasync3,
317 testasync4,
318}
319
320func main() {
321 for _, mk := range mks {
322 test1(mk(closedsync()))
323 }
324
325 for _, testclosed := range testcloseds {
326 for _, mk := range mks {
327 testclosed(mk(closedasync()))
328 }
329 }
Russ Coxf58ed4e2011-10-13 16:58:04 -0400330
331 var ch chan int
332 shouldPanic(func() {
333 close(ch)
334 })
335
336 ch = make(chan int)
337 close(ch)
338 shouldPanic(func() {
339 close(ch)
340 })
Russ Cox13584f42009-03-23 18:50:35 -0700341}