// 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) }