blob: 043a92d3880e83fb8aef11cc358bf1e49d02a7ab [file] [log] [blame]
Russ Cox0b477ef2012-02-16 23:48:57 -05001// run
Russ Cox13584f42009-03-23 18:50:35 -07002
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
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -070014import "os"
15
16var failed bool
17
Russ Cox13584f42009-03-23 18:50:35 -070018type Chan interface {
Rob Pike4f61fc92010-09-04 10:36:13 +100019 Send(int)
20 Nbsend(int) bool
Russ Cox3f915f52011-03-11 14:47:44 -050021 Recv() (int)
Rob Pike4f61fc92010-09-04 10:36:13 +100022 Nbrecv() (int, bool)
Russ Cox3f915f52011-03-11 14:47:44 -050023 Recv2() (int, bool)
24 Nbrecv2() (int, bool, bool)
Rob Pike4f61fc92010-09-04 10:36:13 +100025 Close()
Rob Pike4f61fc92010-09-04 10:36:13 +100026 Impl() string
Russ Cox13584f42009-03-23 18:50:35 -070027}
28
Russ Coxf4e76d82011-01-31 18:36:28 -050029// direct channel operations when possible
Russ Cox13584f42009-03-23 18:50:35 -070030type XChan chan int
Russ Coxf4e76d82011-01-31 18:36:28 -050031
Russ Cox13584f42009-03-23 18:50:35 -070032func (c XChan) Send(x int) {
33 c <- x
34}
35
36func (c XChan) Nbsend(x int) bool {
Russ Coxf4e76d82011-01-31 18:36:28 -050037 select {
38 case c <- x:
39 return true
40 default:
41 return false
42 }
43 panic("nbsend")
Russ Cox13584f42009-03-23 18:50:35 -070044}
45
46func (c XChan) Recv() int {
47 return <-c
48}
49
50func (c XChan) Nbrecv() (int, bool) {
Russ Coxf4e76d82011-01-31 18:36:28 -050051 select {
52 case x := <-c:
53 return x, true
54 default:
55 return 0, false
56 }
57 panic("nbrecv")
Russ Cox13584f42009-03-23 18:50:35 -070058}
59
Russ Cox3f915f52011-03-11 14:47:44 -050060func (c XChan) Recv2() (int, bool) {
61 x, ok := <-c
62 return x, ok
Russ Cox13584f42009-03-23 18:50:35 -070063}
64
Russ Cox3f915f52011-03-11 14:47:44 -050065func (c XChan) Nbrecv2() (int, bool, bool) {
66 select {
67 case x, ok := <-c:
68 return x, ok, true
69 default:
70 return 0, false, false
71 }
72 panic("nbrecv2")
73}
74
75func (c XChan) Close() {
76 close(c)
Russ Cox13584f42009-03-23 18:50:35 -070077}
78
79func (c XChan) Impl() string {
80 return "(<- operator)"
81}
82
83// indirect operations via select
84type SChan chan int
Russ Coxf4e76d82011-01-31 18:36:28 -050085
Russ Cox13584f42009-03-23 18:50:35 -070086func (c SChan) Send(x int) {
87 select {
88 case c <- x:
89 }
90}
91
92func (c SChan) Nbsend(x int) bool {
93 select {
Russ Cox13584f42009-03-23 18:50:35 -070094 default:
Rob Pike4f61fc92010-09-04 10:36:13 +100095 return false
Russ Coxf4e76d82011-01-31 18:36:28 -050096 case c <- x:
97 return true
Russ Cox13584f42009-03-23 18:50:35 -070098 }
Rob Pike4f61fc92010-09-04 10:36:13 +100099 panic("nbsend")
Russ Cox13584f42009-03-23 18:50:35 -0700100}
101
102func (c SChan) Recv() int {
103 select {
104 case x := <-c:
Rob Pike4f61fc92010-09-04 10:36:13 +1000105 return x
Russ Cox13584f42009-03-23 18:50:35 -0700106 }
Rob Pike4f61fc92010-09-04 10:36:13 +1000107 panic("recv")
Russ Cox13584f42009-03-23 18:50:35 -0700108}
109
110func (c SChan) Nbrecv() (int, bool) {
111 select {
Russ Cox13584f42009-03-23 18:50:35 -0700112 default:
Rob Pike4f61fc92010-09-04 10:36:13 +1000113 return 0, false
Russ Coxf4e76d82011-01-31 18:36:28 -0500114 case x := <-c:
115 return x, true
Russ Cox13584f42009-03-23 18:50:35 -0700116 }
Rob Pike4f61fc92010-09-04 10:36:13 +1000117 panic("nbrecv")
Russ Cox13584f42009-03-23 18:50:35 -0700118}
119
Russ Cox3f915f52011-03-11 14:47:44 -0500120func (c SChan) Recv2() (int, bool) {
121 select {
122 case x, ok := <-c:
123 return x, ok
124 }
125 panic("recv")
Russ Cox13584f42009-03-23 18:50:35 -0700126}
127
Russ Cox3f915f52011-03-11 14:47:44 -0500128func (c SChan) Nbrecv2() (int, bool, bool) {
129 select {
130 default:
131 return 0, false, false
132 case x, ok := <-c:
133 return x, ok, true
134 }
135 panic("nbrecv")
136}
137
138func (c SChan) Close() {
139 close(c)
Russ Cox13584f42009-03-23 18:50:35 -0700140}
141
142func (c SChan) Impl() string {
Rob Pike4f61fc92010-09-04 10:36:13 +1000143 return "(select)"
Russ Cox13584f42009-03-23 18:50:35 -0700144}
145
Russ Coxf4e76d82011-01-31 18:36:28 -0500146// indirect operations via larger selects
147var dummy = make(chan bool)
148
149type SSChan chan int
150
151func (c SSChan) Send(x int) {
152 select {
153 case c <- x:
154 case <-dummy:
155 }
156}
157
158func (c SSChan) Nbsend(x int) bool {
159 select {
160 default:
161 return false
162 case <-dummy:
163 case c <- x:
164 return true
165 }
166 panic("nbsend")
167}
168
169func (c SSChan) Recv() int {
170 select {
171 case <-dummy:
172 case x := <-c:
173 return x
174 }
175 panic("recv")
176}
177
178func (c SSChan) Nbrecv() (int, bool) {
179 select {
180 case <-dummy:
181 default:
182 return 0, false
183 case x := <-c:
184 return x, true
185 }
186 panic("nbrecv")
187}
188
Russ Cox3f915f52011-03-11 14:47:44 -0500189func (c SSChan) Recv2() (int, bool) {
190 select {
191 case <-dummy:
192 case x, ok := <-c:
193 return x, ok
194 }
195 panic("recv")
Russ Coxf4e76d82011-01-31 18:36:28 -0500196}
197
Russ Cox3f915f52011-03-11 14:47:44 -0500198func (c SSChan) Nbrecv2() (int, bool, bool) {
199 select {
200 case <-dummy:
201 default:
202 return 0, false, false
203 case x, ok := <-c:
204 return x, ok, true
205 }
206 panic("nbrecv")
207}
208
209func (c SSChan) Close() {
210 close(c)
Russ Coxf4e76d82011-01-31 18:36:28 -0500211}
212
213func (c SSChan) Impl() string {
214 return "(select)"
215}
216
217
Russ Cox27c74d32011-01-21 15:07:13 -0500218func shouldPanic(f func()) {
219 defer func() {
220 if recover() == nil {
221 panic("did not panic")
222 }
223 }()
224 f()
225}
226
Russ Cox13584f42009-03-23 18:50:35 -0700227func test1(c Chan) {
Russ Cox13584f42009-03-23 18:50:35 -0700228 for i := 0; i < 3; i++ {
229 // recv a close signal (a zero value)
230 if x := c.Recv(); x != 0 {
Russ Cox3f915f52011-03-11 14:47:44 -0500231 println("test1: recv on closed:", x, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700232 failed = true
Russ Cox3f915f52011-03-11 14:47:44 -0500233 }
234 if x, ok := c.Recv2(); x != 0 || ok {
235 println("test1: recv2 on closed:", x, ok, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700236 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700237 }
238
Russ Cox3f915f52011-03-11 14:47:44 -0500239 // should work with select: received a value without blocking, so selected == true.
240 x, selected := c.Nbrecv()
241 if x != 0 || !selected {
242 println("test1: recv on closed nb:", x, selected, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700243 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700244 }
Russ Cox3f915f52011-03-11 14:47:44 -0500245 x, ok, selected := c.Nbrecv2()
246 if x != 0 || ok || !selected {
247 println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700248 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700249 }
250 }
251
252 // send should work with ,ok too: sent a value without blocking, so ok == true.
Russ Coxf4e76d82011-01-31 18:36:28 -0500253 shouldPanic(func() { c.Nbsend(1) })
Russ Cox13584f42009-03-23 18:50:35 -0700254
Russ Cox27c74d32011-01-21 15:07:13 -0500255 // the value should have been discarded.
Russ Cox13584f42009-03-23 18:50:35 -0700256 if x := c.Recv(); x != 0 {
Rob Pike4f61fc92010-09-04 10:36:13 +1000257 println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700258 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700259 }
260
261 // similarly Send.
Russ Coxf4e76d82011-01-31 18:36:28 -0500262 shouldPanic(func() { c.Send(2) })
Russ Cox13584f42009-03-23 18:50:35 -0700263 if x := c.Recv(); x != 0 {
Rob Pike4f61fc92010-09-04 10:36:13 +1000264 println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700265 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700266 }
267}
268
269func testasync1(c Chan) {
Russ Cox13584f42009-03-23 18:50:35 -0700270 // should be able to get the last value via Recv
271 if x := c.Recv(); x != 1 {
Rob Pike4f61fc92010-09-04 10:36:13 +1000272 println("testasync1: Recv did not get 1:", x, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700273 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700274 }
275
Rob Pike4f61fc92010-09-04 10:36:13 +1000276 test1(c)
Russ Cox13584f42009-03-23 18:50:35 -0700277}
278
279func testasync2(c Chan) {
Russ Cox3f915f52011-03-11 14:47:44 -0500280 // should be able to get the last value via Recv2
281 if x, ok := c.Recv2(); x != 1 || !ok {
282 println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700283 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700284 }
285
Russ Cox3f915f52011-03-11 14:47:44 -0500286 test1(c)
287}
288
289func testasync3(c Chan) {
Russ Cox13584f42009-03-23 18:50:35 -0700290 // should be able to get the last value via Nbrecv
Russ Cox3f915f52011-03-11 14:47:44 -0500291 if x, selected := c.Nbrecv(); x != 1 || !selected {
292 println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700293 failed = true
Russ Cox13584f42009-03-23 18:50:35 -0700294 }
295
Rob Pike4f61fc92010-09-04 10:36:13 +1000296 test1(c)
Russ Cox13584f42009-03-23 18:50:35 -0700297}
298
Russ Cox3f915f52011-03-11 14:47:44 -0500299func testasync4(c Chan) {
300 // should be able to get the last value via Nbrecv2
301 if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
302 println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700303 failed = true
Russ Cox3f915f52011-03-11 14:47:44 -0500304 }
305 test1(c)
306}
307
Russ Cox13584f42009-03-23 18:50:35 -0700308func closedsync() chan int {
Rob Pike4f61fc92010-09-04 10:36:13 +1000309 c := make(chan int)
310 close(c)
311 return c
Russ Cox13584f42009-03-23 18:50:35 -0700312}
313
314func closedasync() chan int {
Rob Pike4f61fc92010-09-04 10:36:13 +1000315 c := make(chan int, 2)
316 c <- 1
317 close(c)
318 return c
Russ Cox13584f42009-03-23 18:50:35 -0700319}
320
Russ Cox3f915f52011-03-11 14:47:44 -0500321var mks = []func(chan int) Chan {
322 func(c chan int) Chan { return XChan(c) },
323 func(c chan int) Chan { return SChan(c) },
324 func(c chan int) Chan { return SSChan(c) },
325}
Russ Cox13584f42009-03-23 18:50:35 -0700326
Russ Cox3f915f52011-03-11 14:47:44 -0500327var testcloseds = []func(Chan) {
328 testasync1,
329 testasync2,
330 testasync3,
331 testasync4,
332}
333
334func main() {
335 for _, mk := range mks {
336 test1(mk(closedsync()))
337 }
338
339 for _, testclosed := range testcloseds {
340 for _, mk := range mks {
341 testclosed(mk(closedasync()))
342 }
343 }
Russ Coxf58ed4e2011-10-13 16:58:04 -0400344
345 var ch chan int
346 shouldPanic(func() {
347 close(ch)
348 })
349
350 ch = make(chan int)
351 close(ch)
352 shouldPanic(func() {
353 close(ch)
354 })
Ian Lance Taylor7f0622e2011-11-04 14:12:35 -0700355
356 if failed {
357 os.Exit(1)
358 }
Russ Cox13584f42009-03-23 18:50:35 -0700359}