2012-02-16 21:48:57 -07:00
|
|
|
// run
|
2010-07-14 10:55:08 -06:00
|
|
|
|
|
|
|
// Copyright 2010 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.
|
|
|
|
|
2012-02-18 23:44:02 -07:00
|
|
|
// Test the semantics of the select statement
|
2010-07-14 10:55:08 -06:00
|
|
|
// for basic empty/non-empty cases.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import "time"
|
|
|
|
|
|
|
|
const always = "function did not"
|
|
|
|
const never = "function did"
|
|
|
|
|
|
|
|
func unreachable() {
|
|
|
|
panic("control flow shouldn't reach here")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls f and verifies that f always/never panics depending on signal.
|
|
|
|
func testPanic(signal string, f func()) {
|
|
|
|
defer func() {
|
|
|
|
s := never
|
|
|
|
if recover() != nil {
|
2010-07-14 14:18:57 -06:00
|
|
|
s = always // f panicked
|
2010-07-14 10:55:08 -06:00
|
|
|
}
|
|
|
|
if s != signal {
|
|
|
|
panic(signal + " panic")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
f()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls f and empirically verifies that f always/never blocks depending on signal.
|
|
|
|
func testBlock(signal string, f func()) {
|
|
|
|
c := make(chan string)
|
|
|
|
go func() {
|
|
|
|
f()
|
|
|
|
c <- never // f didn't block
|
|
|
|
}()
|
|
|
|
go func() {
|
2017-07-07 17:09:20 -06:00
|
|
|
if signal == never {
|
|
|
|
// Wait a long time to make sure that we don't miss our window by accident on a slow machine.
|
|
|
|
time.Sleep(10 * time.Second)
|
|
|
|
} else {
|
|
|
|
// Wait as short a time as we can without false negatives.
|
|
|
|
// 10ms should be long enough to catch most failures.
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
}
|
|
|
|
c <- always // f blocked always
|
2010-07-14 10:55:08 -06:00
|
|
|
}()
|
|
|
|
if <-c != signal {
|
|
|
|
panic(signal + " block")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
const async = 1 // asynchronous channels
|
|
|
|
var nilch chan int
|
2010-07-14 14:18:57 -06:00
|
|
|
closedch := make(chan int)
|
|
|
|
close(closedch)
|
2010-07-14 10:55:08 -06:00
|
|
|
|
2011-08-17 13:54:17 -06:00
|
|
|
// sending/receiving from a nil channel blocks
|
|
|
|
testBlock(always, func() {
|
2010-07-14 10:55:08 -06:00
|
|
|
nilch <- 7
|
|
|
|
})
|
2011-08-17 13:54:17 -06:00
|
|
|
testBlock(always, func() {
|
2010-07-14 10:55:08 -06:00
|
|
|
<-nilch
|
|
|
|
})
|
|
|
|
|
2011-08-17 13:54:17 -06:00
|
|
|
// sending/receiving from a nil channel inside a select is never selected
|
2010-07-14 10:55:08 -06:00
|
|
|
testPanic(never, func() {
|
|
|
|
select {
|
|
|
|
case nilch <- 7:
|
|
|
|
unreachable()
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testPanic(never, func() {
|
|
|
|
select {
|
|
|
|
case <-nilch:
|
|
|
|
unreachable()
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// sending to an async channel with free buffer space never blocks
|
|
|
|
testBlock(never, func() {
|
|
|
|
ch := make(chan int, async)
|
|
|
|
ch <- 7
|
|
|
|
})
|
|
|
|
|
2011-03-11 12:47:44 -07:00
|
|
|
// receiving from a closed channel never blocks
|
2010-07-14 14:18:57 -06:00
|
|
|
testBlock(never, func() {
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
if <-closedch != 0 {
|
|
|
|
panic("expected zero value when reading from closed channel")
|
|
|
|
}
|
2011-03-11 12:47:44 -07:00
|
|
|
if x, ok := <-closedch; x != 0 || ok {
|
|
|
|
println("closedch:", x, ok)
|
|
|
|
panic("expected 0, false from closed channel")
|
|
|
|
}
|
2010-07-14 14:18:57 -06:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
spec, runtime, tests: send on closed channel panics
Close of closed channel panics.
Receive from closed channel never panics,
even if done repeatedly.
Fixes #1349.
Fixes #1419.
R=gri, iant, ken2, r, gri1, r2, iant2, rog, albert.strasheim, niemeyer, ejsherry
CC=golang-dev
https://golang.org/cl/3989042
2011-01-21 13:07:13 -07:00
|
|
|
// sending to a closed channel panics.
|
|
|
|
testPanic(always, func() {
|
|
|
|
closedch <- 7
|
2010-07-14 14:18:57 -06:00
|
|
|
})
|
|
|
|
|
2010-07-14 10:55:08 -06:00
|
|
|
// receiving from a non-ready channel always blocks
|
|
|
|
testBlock(always, func() {
|
|
|
|
ch := make(chan int)
|
|
|
|
<-ch
|
|
|
|
})
|
|
|
|
|
2010-08-03 02:07:57 -06:00
|
|
|
// empty selects always block
|
|
|
|
testBlock(always, func() {
|
2017-05-18 15:53:12 -06:00
|
|
|
select {}
|
2010-08-03 02:07:57 -06:00
|
|
|
})
|
2010-07-14 10:55:08 -06:00
|
|
|
|
2010-08-03 02:07:57 -06:00
|
|
|
// selects with only nil channels always block
|
|
|
|
testBlock(always, func() {
|
|
|
|
select {
|
|
|
|
case <-nilch:
|
|
|
|
unreachable()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testBlock(always, func() {
|
|
|
|
select {
|
|
|
|
case nilch <- 7:
|
|
|
|
unreachable()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testBlock(always, func() {
|
|
|
|
select {
|
|
|
|
case <-nilch:
|
|
|
|
unreachable()
|
|
|
|
case nilch <- 7:
|
|
|
|
unreachable()
|
|
|
|
}
|
|
|
|
})
|
2010-07-14 10:55:08 -06:00
|
|
|
|
|
|
|
// selects with non-ready non-nil channels always block
|
|
|
|
testBlock(always, func() {
|
|
|
|
ch := make(chan int)
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
unreachable()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// selects with default cases don't block
|
|
|
|
testBlock(never, func() {
|
|
|
|
select {
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testBlock(never, func() {
|
|
|
|
select {
|
|
|
|
case <-nilch:
|
|
|
|
unreachable()
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testBlock(never, func() {
|
|
|
|
select {
|
|
|
|
case nilch <- 7:
|
|
|
|
unreachable()
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// selects with ready channels don't block
|
|
|
|
testBlock(never, func() {
|
|
|
|
ch := make(chan int, async)
|
|
|
|
select {
|
|
|
|
case ch <- 7:
|
|
|
|
default:
|
|
|
|
unreachable()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testBlock(never, func() {
|
|
|
|
ch := make(chan int, async)
|
|
|
|
ch <- 7
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
default:
|
|
|
|
unreachable()
|
|
|
|
}
|
|
|
|
})
|
2010-07-14 14:18:57 -06:00
|
|
|
|
spec, runtime, tests: send on closed channel panics
Close of closed channel panics.
Receive from closed channel never panics,
even if done repeatedly.
Fixes #1349.
Fixes #1419.
R=gri, iant, ken2, r, gri1, r2, iant2, rog, albert.strasheim, niemeyer, ejsherry
CC=golang-dev
https://golang.org/cl/3989042
2011-01-21 13:07:13 -07:00
|
|
|
// selects with closed channels behave like ordinary operations
|
2010-07-14 14:18:57 -06:00
|
|
|
testBlock(never, func() {
|
|
|
|
select {
|
|
|
|
case <-closedch:
|
|
|
|
}
|
|
|
|
})
|
2011-03-11 12:47:44 -07:00
|
|
|
testBlock(never, func() {
|
|
|
|
select {
|
2012-02-01 08:31:00 -07:00
|
|
|
case x := (<-closedch):
|
2011-03-11 12:47:44 -07:00
|
|
|
_ = x
|
|
|
|
}
|
|
|
|
})
|
|
|
|
testBlock(never, func() {
|
|
|
|
select {
|
2012-02-01 08:31:00 -07:00
|
|
|
case x, ok := (<-closedch):
|
2011-03-11 12:47:44 -07:00
|
|
|
_, _ = x, ok
|
|
|
|
}
|
|
|
|
})
|
spec, runtime, tests: send on closed channel panics
Close of closed channel panics.
Receive from closed channel never panics,
even if done repeatedly.
Fixes #1349.
Fixes #1419.
R=gri, iant, ken2, r, gri1, r2, iant2, rog, albert.strasheim, niemeyer, ejsherry
CC=golang-dev
https://golang.org/cl/3989042
2011-01-21 13:07:13 -07:00
|
|
|
testPanic(always, func() {
|
2010-07-14 14:18:57 -06:00
|
|
|
select {
|
|
|
|
case closedch <- 7:
|
|
|
|
}
|
|
|
|
})
|
2011-03-11 12:47:44 -07:00
|
|
|
|
2011-01-28 15:17:38 -07:00
|
|
|
// select should not get confused if it sees itself
|
|
|
|
testBlock(always, func() {
|
|
|
|
c := make(chan int)
|
|
|
|
select {
|
|
|
|
case c <- 1:
|
|
|
|
case <-c:
|
|
|
|
}
|
|
|
|
})
|
2010-07-14 10:55:08 -06:00
|
|
|
}
|