diff options
Diffstat (limited to '')
-rw-r--r-- | test/ken/chan.go | 331 |
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) +} |