| // $G $D/$F.go && $L $F.$A && ./$A.out |
| |
| // 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. |
| |
| package main |
| |
| import "os" |
| import "runtime" |
| |
| 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; |
| cval int; |
| end int = 10000; |
| totr,tots int; |
| nc *Chan; |
| ) |
| |
| func |
| init() |
| { |
| nc = new(Chan); |
| } |
| |
| 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; |
| } |
| panic("got ", v, " expected ", v0+1, "\n"); |
| } |
| |
| func (c *Chan) |
| send() bool |
| { |
| // print("send ", c.sv, "\n"); |
| tots++; |
| c.sv = expect(c.sv, c.sv); |
| if c.sv == end { |
| c.sc = nil; |
| return true; |
| } |
| return false; |
| } |
| |
| func |
| send(c *Chan) |
| { |
| nproc++; // total goroutines running |
| for { |
| for r:=nrand(10); r>=0; r-- { |
| runtime.Gosched(); |
| } |
| c.sc <- c.sv; |
| if c.send() { |
| break; |
| } |
| } |
| nproc--; |
| } |
| |
| func (c *Chan) |
| recv(v int) bool |
| { |
| // print("recv ", v, "\n"); |
| totr++; |
| c.rv = expect(c.rv, v); |
| if c.rv == end { |
| c.rc = nil; |
| return true; |
| } |
| return false; |
| } |
| |
| func |
| recv(c *Chan) |
| { |
| var v int; |
| |
| nproc++; // total goroutines running |
| for { |
| for r:=nrand(10); r>=0; r-- { |
| runtime.Gosched(); |
| } |
| v = <-c.rc; |
| if c.recv(v) { |
| break; |
| } |
| } |
| nproc--; |
| } |
| |
| func |
| sel(r0,r1,r2,r3, s0,s1,s2,s3 *Chan) |
| { |
| var v int; |
| |
| nproc++; // total goroutines running |
| 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; |
| } |
| } |
| nproc--; |
| } |
| |
| // direct send to direct recv |
| func |
| test1(c *Chan) |
| { |
| go send(c); |
| go recv(c); |
| } |
| |
| // direct send to select recv |
| func |
| test2(c int) |
| { |
| ca := mkchan(c,4); |
| |
| go send(ca[0]); |
| go send(ca[1]); |
| go send(ca[2]); |
| go send(ca[3]); |
| |
| 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); |
| |
| go recv(ca[0]); |
| go recv(ca[1]); |
| go recv(ca[2]); |
| go recv(ca[3]); |
| |
| 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); |
| |
| 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); |
| |
| 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); |
| |
| go send(ca[4]); |
| go send(ca[5]); |
| go send(ca[6]); |
| go send(ca[7]); |
| |
| go recv(ca[8]); |
| go recv(ca[9]); |
| go recv(ca[10]); |
| go recv(ca[11]); |
| |
| 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 nproc != 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); |
| } |