1// run
2
3// Copyright 2009 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// Test communication operations including select.
8
9package main
10
11import "os"
12import "runtime"
13import "sync"
14
15var randx int
16
17func nrand(n int) int {
18	randx += 10007
19	if randx >= 1000000 {
20		randx -= 1000000
21	}
22	return randx % n
23}
24
25type Chan struct {
26	sc, rc chan int // send and recv chan
27	sv, rv int      // send and recv seq
28}
29
30var (
31	nproc      int
32	nprocLock  sync.Mutex
33	cval       int
34	end        int = 10000
35	totr, tots int
36	totLock    sync.Mutex
37	nc         *Chan
38)
39
40func init() {
41	nc = new(Chan)
42}
43
44func changeNproc(adjust int) int {
45	nprocLock.Lock()
46	nproc += adjust
47	ret := nproc
48	nprocLock.Unlock()
49	return ret
50}
51
52func mkchan(c, n int) []*Chan {
53	ca := make([]*Chan, n)
54	for i := 0; i < n; i++ {
55		cval = cval + 100
56		ch := new(Chan)
57		ch.sc = make(chan int, c)
58		ch.rc = ch.sc
59		ch.sv = cval
60		ch.rv = cval
61		ca[i] = ch
62	}
63	return ca
64}
65
66func expect(v, v0 int) (newv int) {
67	if v == v0 {
68		if v%100 == 75 {
69			return end
70		}
71		return v + 1
72	}
73	print("got ", v, " expected ", v0+1, "\n")
74	panic("fail")
75}
76
77func (c *Chan) send() bool {
78	//	print("send ", c.sv, "\n");
79	totLock.Lock()
80	tots++
81	totLock.Unlock()
82	c.sv = expect(c.sv, c.sv)
83	if c.sv == end {
84		c.sc = nil
85		return true
86	}
87	return false
88}
89
90func send(c *Chan) {
91	for {
92		for r := nrand(10); r >= 0; r-- {
93			runtime.Gosched()
94		}
95		c.sc <- c.sv
96		if c.send() {
97			break
98		}
99	}
100	changeNproc(-1)
101}
102
103func (c *Chan) recv(v int) bool {
104	//	print("recv ", v, "\n");
105	totLock.Lock()
106	totr++
107	totLock.Unlock()
108	c.rv = expect(c.rv, v)
109	if c.rv == end {
110		c.rc = nil
111		return true
112	}
113	return false
114}
115
116func recv(c *Chan) {
117	var v int
118
119	for {
120		for r := nrand(10); r >= 0; r-- {
121			runtime.Gosched()
122		}
123		v = <-c.rc
124		if c.recv(v) {
125			break
126		}
127	}
128	changeNproc(-1)
129}
130
131func sel(r0, r1, r2, r3, s0, s1, s2, s3 *Chan) {
132	var v int
133
134	a := 0 // local chans running
135
136	if r0.rc != nil {
137		a++
138	}
139	if r1.rc != nil {
140		a++
141	}
142	if r2.rc != nil {
143		a++
144	}
145	if r3.rc != nil {
146		a++
147	}
148	if s0.sc != nil {
149		a++
150	}
151	if s1.sc != nil {
152		a++
153	}
154	if s2.sc != nil {
155		a++
156	}
157	if s3.sc != nil {
158		a++
159	}
160
161	for {
162		for r := nrand(5); r >= 0; r-- {
163			runtime.Gosched()
164		}
165
166		select {
167		case v = <-r0.rc:
168			if r0.recv(v) {
169				a--
170			}
171		case v = <-r1.rc:
172			if r1.recv(v) {
173				a--
174			}
175		case v = <-r2.rc:
176			if r2.recv(v) {
177				a--
178			}
179		case v = <-r3.rc:
180			if r3.recv(v) {
181				a--
182			}
183		case s0.sc <- s0.sv:
184			if s0.send() {
185				a--
186			}
187		case s1.sc <- s1.sv:
188			if s1.send() {
189				a--
190			}
191		case s2.sc <- s2.sv:
192			if s2.send() {
193				a--
194			}
195		case s3.sc <- s3.sv:
196			if s3.send() {
197				a--
198			}
199		}
200		if a == 0 {
201			break
202		}
203	}
204	changeNproc(-1)
205}
206
207// direct send to direct recv
208func test1(c *Chan) {
209	changeNproc(2)
210	go send(c)
211	go recv(c)
212}
213
214// direct send to select recv
215func test2(c int) {
216	ca := mkchan(c, 4)
217
218	changeNproc(4)
219	go send(ca[0])
220	go send(ca[1])
221	go send(ca[2])
222	go send(ca[3])
223
224	changeNproc(1)
225	go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
226}
227
228// select send to direct recv
229func test3(c int) {
230	ca := mkchan(c, 4)
231
232	changeNproc(4)
233	go recv(ca[0])
234	go recv(ca[1])
235	go recv(ca[2])
236	go recv(ca[3])
237
238	changeNproc(1)
239	go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
240}
241
242// select send to select recv
243func test4(c int) {
244	ca := mkchan(c, 4)
245
246	changeNproc(2)
247	go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
248	go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
249}
250
251func test5(c int) {
252	ca := mkchan(c, 8)
253
254	changeNproc(2)
255	go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
256	go sel(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7])
257}
258
259func test6(c int) {
260	ca := mkchan(c, 12)
261
262	changeNproc(4)
263	go send(ca[4])
264	go send(ca[5])
265	go send(ca[6])
266	go send(ca[7])
267
268	changeNproc(4)
269	go recv(ca[8])
270	go recv(ca[9])
271	go recv(ca[10])
272	go recv(ca[11])
273
274	changeNproc(2)
275	go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
276	go sel(ca[0], ca[1], ca[2], ca[3], ca[8], ca[9], ca[10], ca[11])
277}
278
279// wait for outstanding tests to finish
280func wait() {
281	runtime.Gosched()
282	for changeNproc(0) != 0 {
283		runtime.Gosched()
284	}
285}
286
287// run all tests with specified buffer size
288func tests(c int) {
289	ca := mkchan(c, 4)
290	test1(ca[0])
291	test1(ca[1])
292	test1(ca[2])
293	test1(ca[3])
294	wait()
295
296	test2(c)
297	wait()
298
299	test3(c)
300	wait()
301
302	test4(c)
303	wait()
304
305	test5(c)
306	wait()
307
308	test6(c)
309	wait()
310}
311
312// run all test with 4 buffser sizes
313func main() {
314
315	tests(0)
316	tests(1)
317	tests(10)
318	tests(100)
319
320	t := 4 * // buffer sizes
321		(4*4 + // tests 1,2,3,4 channels
322			8 + // test 5 channels
323			12) * // test 6 channels
324		76 // sends/recvs on a channel
325
326	if tots != t || totr != t {
327		print("tots=", tots, " totr=", totr, " sb=", t, "\n")
328		os.Exit(1)
329	}
330	os.Exit(0)
331}
332