1// run 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), receive of closed channel. 8// 9// TODO(rsc): Doesn't check behavior of close(c) when there 10// are blocked senders/receivers. 11 12package main 13 14import "os" 15 16var failed bool 17 18type Chan interface { 19 Send(int) 20 Nbsend(int) bool 21 Recv() (int) 22 Nbrecv() (int, bool) 23 Recv2() (int, bool) 24 Nbrecv2() (int, bool, bool) 25 Close() 26 Impl() string 27} 28 29// direct channel operations when possible 30type XChan chan int 31 32func (c XChan) Send(x int) { 33 c <- x 34} 35 36func (c XChan) Nbsend(x int) bool { 37 select { 38 case c <- x: 39 return true 40 default: 41 return false 42 } 43 panic("nbsend") 44} 45 46func (c XChan) Recv() int { 47 return <-c 48} 49 50func (c XChan) Nbrecv() (int, bool) { 51 select { 52 case x := <-c: 53 return x, true 54 default: 55 return 0, false 56 } 57 panic("nbrecv") 58} 59 60func (c XChan) Recv2() (int, bool) { 61 x, ok := <-c 62 return x, ok 63} 64 65func (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) 77} 78 79func (c XChan) Impl() string { 80 return "(<- operator)" 81} 82 83// indirect operations via select 84type SChan chan int 85 86func (c SChan) Send(x int) { 87 select { 88 case c <- x: 89 } 90} 91 92func (c SChan) Nbsend(x int) bool { 93 select { 94 default: 95 return false 96 case c <- x: 97 return true 98 } 99 panic("nbsend") 100} 101 102func (c SChan) Recv() int { 103 select { 104 case x := <-c: 105 return x 106 } 107 panic("recv") 108} 109 110func (c SChan) Nbrecv() (int, bool) { 111 select { 112 default: 113 return 0, false 114 case x := <-c: 115 return x, true 116 } 117 panic("nbrecv") 118} 119 120func (c SChan) Recv2() (int, bool) { 121 select { 122 case x, ok := <-c: 123 return x, ok 124 } 125 panic("recv") 126} 127 128func (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) 140} 141 142func (c SChan) Impl() string { 143 return "(select)" 144} 145 146// 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 189func (c SSChan) Recv2() (int, bool) { 190 select { 191 case <-dummy: 192 case x, ok := <-c: 193 return x, ok 194 } 195 panic("recv") 196} 197 198func (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) 211} 212 213func (c SSChan) Impl() string { 214 return "(select)" 215} 216 217 218func shouldPanic(f func()) { 219 defer func() { 220 if recover() == nil { 221 panic("did not panic") 222 } 223 }() 224 f() 225} 226 227func test1(c Chan) { 228 for i := 0; i < 3; i++ { 229 // recv a close signal (a zero value) 230 if x := c.Recv(); x != 0 { 231 println("test1: recv on closed:", x, c.Impl()) 232 failed = true 233 } 234 if x, ok := c.Recv2(); x != 0 || ok { 235 println("test1: recv2 on closed:", x, ok, c.Impl()) 236 failed = true 237 } 238 239 // 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()) 243 failed = true 244 } 245 x, ok, selected := c.Nbrecv2() 246 if x != 0 || ok || !selected { 247 println("test1: recv2 on closed nb:", x, ok, selected, c.Impl()) 248 failed = true 249 } 250 } 251 252 // send should work with ,ok too: sent a value without blocking, so ok == true. 253 shouldPanic(func() { c.Nbsend(1) }) 254 255 // the value should have been discarded. 256 if x := c.Recv(); x != 0 { 257 println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) 258 failed = true 259 } 260 261 // similarly Send. 262 shouldPanic(func() { c.Send(2) }) 263 if x := c.Recv(); x != 0 { 264 println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) 265 failed = true 266 } 267} 268 269func testasync1(c Chan) { 270 // should be able to get the last value via Recv 271 if x := c.Recv(); x != 1 { 272 println("testasync1: Recv did not get 1:", x, c.Impl()) 273 failed = true 274 } 275 276 test1(c) 277} 278 279func testasync2(c Chan) { 280 // 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()) 283 failed = true 284 } 285 286 test1(c) 287} 288 289func testasync3(c Chan) { 290 // should be able to get the last value via Nbrecv 291 if x, selected := c.Nbrecv(); x != 1 || !selected { 292 println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl()) 293 failed = true 294 } 295 296 test1(c) 297} 298 299func 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()) 303 failed = true 304 } 305 test1(c) 306} 307 308func closedsync() chan int { 309 c := make(chan int) 310 close(c) 311 return c 312} 313 314func closedasync() chan int { 315 c := make(chan int, 2) 316 c <- 1 317 close(c) 318 return c 319} 320 321var 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} 326 327var 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 } 344 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 }) 355 356 if failed { 357 os.Exit(1) 358 } 359} 360