summaryrefslogtreecommitdiffstats
path: root/test/ken/chan.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/ken/chan.go')
-rw-r--r--test/ken/chan.go331
1 files changed, 331 insertions, 0 deletions
diff --git a/test/ken/chan.go b/test/ken/chan.go
new file mode 100644
index 0000000..36b18f8
--- /dev/null
+++ b/test/ken/chan.go
@@ -0,0 +1,331 @@
+// run
+
+// Copyright 2009 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.
+
+// Test communication operations including select.
+
+package main
+
+import "os"
+import "runtime"
+import "sync"
+
+var randx int
+
+func nrand(n int) int {
+ randx += 10007
+ if randx >= 1000000 {
+ randx -= 1000000
+ }
+ return randx % n
+}
+
+type Chan struct {
+ sc, rc chan int // send and recv chan
+ sv, rv int // send and recv seq
+}
+
+var (
+ nproc int
+ nprocLock sync.Mutex
+ cval int
+ end int = 10000
+ totr, tots int
+ totLock sync.Mutex
+ nc *Chan
+)
+
+func init() {
+ nc = new(Chan)
+}
+
+func changeNproc(adjust int) int {
+ nprocLock.Lock()
+ nproc += adjust
+ ret := nproc
+ nprocLock.Unlock()
+ return ret
+}
+
+func mkchan(c, n int) []*Chan {
+ ca := make([]*Chan, n)
+ for i := 0; i < n; i++ {
+ cval = cval + 100
+ ch := new(Chan)
+ ch.sc = make(chan int, c)
+ ch.rc = ch.sc
+ ch.sv = cval
+ ch.rv = cval
+ ca[i] = ch
+ }
+ return ca
+}
+
+func expect(v, v0 int) (newv int) {
+ if v == v0 {
+ if v%100 == 75 {
+ return end
+ }
+ return v + 1
+ }
+ print("got ", v, " expected ", v0+1, "\n")
+ panic("fail")
+}
+
+func (c *Chan) send() bool {
+ // print("send ", c.sv, "\n");
+ totLock.Lock()
+ tots++
+ totLock.Unlock()
+ c.sv = expect(c.sv, c.sv)
+ if c.sv == end {
+ c.sc = nil
+ return true
+ }
+ return false
+}
+
+func send(c *Chan) {
+ for {
+ for r := nrand(10); r >= 0; r-- {
+ runtime.Gosched()
+ }
+ c.sc <- c.sv
+ if c.send() {
+ break
+ }
+ }
+ changeNproc(-1)
+}
+
+func (c *Chan) recv(v int) bool {
+ // print("recv ", v, "\n");
+ totLock.Lock()
+ totr++
+ totLock.Unlock()
+ c.rv = expect(c.rv, v)
+ if c.rv == end {
+ c.rc = nil
+ return true
+ }
+ return false
+}
+
+func recv(c *Chan) {
+ var v int
+
+ for {
+ for r := nrand(10); r >= 0; r-- {
+ runtime.Gosched()
+ }
+ v = <-c.rc
+ if c.recv(v) {
+ break
+ }
+ }
+ changeNproc(-1)
+}
+
+func sel(r0, r1, r2, r3, s0, s1, s2, s3 *Chan) {
+ var v int
+
+ a := 0 // local chans running
+
+ if r0.rc != nil {
+ a++
+ }
+ if r1.rc != nil {
+ a++
+ }
+ if r2.rc != nil {
+ a++
+ }
+ if r3.rc != nil {
+ a++
+ }
+ if s0.sc != nil {
+ a++
+ }
+ if s1.sc != nil {
+ a++
+ }
+ if s2.sc != nil {
+ a++
+ }
+ if s3.sc != nil {
+ a++
+ }
+
+ for {
+ for r := nrand(5); r >= 0; r-- {
+ runtime.Gosched()
+ }
+
+ select {
+ case v = <-r0.rc:
+ if r0.recv(v) {
+ a--
+ }
+ case v = <-r1.rc:
+ if r1.recv(v) {
+ a--
+ }
+ case v = <-r2.rc:
+ if r2.recv(v) {
+ a--
+ }
+ case v = <-r3.rc:
+ if r3.recv(v) {
+ a--
+ }
+ case s0.sc <- s0.sv:
+ if s0.send() {
+ a--
+ }
+ case s1.sc <- s1.sv:
+ if s1.send() {
+ a--
+ }
+ case s2.sc <- s2.sv:
+ if s2.send() {
+ a--
+ }
+ case s3.sc <- s3.sv:
+ if s3.send() {
+ a--
+ }
+ }
+ if a == 0 {
+ break
+ }
+ }
+ changeNproc(-1)
+}
+
+// direct send to direct recv
+func test1(c *Chan) {
+ changeNproc(2)
+ go send(c)
+ go recv(c)
+}
+
+// direct send to select recv
+func test2(c int) {
+ ca := mkchan(c, 4)
+
+ changeNproc(4)
+ go send(ca[0])
+ go send(ca[1])
+ go send(ca[2])
+ go send(ca[3])
+
+ changeNproc(1)
+ go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
+}
+
+// select send to direct recv
+func test3(c int) {
+ ca := mkchan(c, 4)
+
+ changeNproc(4)
+ go recv(ca[0])
+ go recv(ca[1])
+ go recv(ca[2])
+ go recv(ca[3])
+
+ changeNproc(1)
+ go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
+}
+
+// select send to select recv
+func test4(c int) {
+ ca := mkchan(c, 4)
+
+ changeNproc(2)
+ go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
+ go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
+}
+
+func test5(c int) {
+ ca := mkchan(c, 8)
+
+ changeNproc(2)
+ go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
+ go sel(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7])
+}
+
+func test6(c int) {
+ ca := mkchan(c, 12)
+
+ changeNproc(4)
+ go send(ca[4])
+ go send(ca[5])
+ go send(ca[6])
+ go send(ca[7])
+
+ changeNproc(4)
+ go recv(ca[8])
+ go recv(ca[9])
+ go recv(ca[10])
+ go recv(ca[11])
+
+ changeNproc(2)
+ go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
+ go sel(ca[0], ca[1], ca[2], ca[3], ca[8], ca[9], ca[10], ca[11])
+}
+
+// wait for outstanding tests to finish
+func wait() {
+ runtime.Gosched()
+ for changeNproc(0) != 0 {
+ runtime.Gosched()
+ }
+}
+
+// run all tests with specified buffer size
+func tests(c int) {
+ ca := mkchan(c, 4)
+ test1(ca[0])
+ test1(ca[1])
+ test1(ca[2])
+ test1(ca[3])
+ wait()
+
+ test2(c)
+ wait()
+
+ test3(c)
+ wait()
+
+ test4(c)
+ wait()
+
+ test5(c)
+ wait()
+
+ test6(c)
+ wait()
+}
+
+// run all test with 4 buffser sizes
+func main() {
+
+ tests(0)
+ tests(1)
+ tests(10)
+ tests(100)
+
+ t := 4 * // buffer sizes
+ (4*4 + // tests 1,2,3,4 channels
+ 8 + // test 5 channels
+ 12) * // test 6 channels
+ 76 // sends/recvs on a channel
+
+ if tots != t || totr != t {
+ print("tots=", tots, " totr=", totr, " sb=", t, "\n")
+ os.Exit(1)
+ }
+ os.Exit(0)
+}