Source file
test/chan/select5.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package main
16
17 import (
18 "bufio"
19 "fmt"
20 "io"
21 "os"
22 "text/template"
23 )
24
25 func main() {
26 out := bufio.NewWriter(os.Stdout)
27 fmt.Fprintln(out, header)
28 a := new(arg)
29
30
31
32
33
34 do := func(t *template.Template) {
35 for ; next(); a.reset() {
36 fmt.Fprintln(out, `func init() {`)
37 run(t, a, out)
38 fmt.Fprintln(out, `}`)
39 }
40 }
41
42 do(recv)
43 do(send)
44 do(recvOrder)
45 do(sendOrder)
46 do(nonblock)
47
48 fmt.Fprintln(out, "//", a.nreset, "cases")
49 out.Flush()
50 }
51
52 func run(t *template.Template, a interface{}, out io.Writer) {
53 if err := t.Execute(out, a); err != nil {
54 panic(err)
55 }
56 }
57
58 type arg struct {
59 def bool
60 nreset int
61 }
62
63 func (a *arg) Maybe() bool {
64 return maybe()
65 }
66
67 func (a *arg) MaybeDefault() bool {
68 if a.def {
69 return false
70 }
71 a.def = maybe()
72 return a.def
73 }
74
75 func (a *arg) MustDefault() bool {
76 return !a.def
77 }
78
79 func (a *arg) reset() {
80 a.def = false
81 a.nreset++
82 }
83
84 const header = `// GENERATED BY select5.go; DO NOT EDIT
85
86 package main
87
88 // channel is buffered so test is single-goroutine.
89 // we are not interested in the concurrency aspects
90 // of select, just testing that the right calls happen.
91 var c = make(chan int, 1)
92 var nilch chan int
93 var n = 1
94 var x int
95 var i interface{}
96 var dummy = make(chan int)
97 var m = make(map[int]int)
98 var order = 0
99
100 func f(p *int) *int {
101 return p
102 }
103
104 // check order of operations by ensuring that
105 // successive calls to checkorder have increasing o values.
106 func checkorder(o int) {
107 if o <= order {
108 println("invalid order", o, "after", order)
109 panic("order")
110 }
111 order = o
112 }
113
114 func fc(c chan int, o int) chan int {
115 checkorder(o)
116 return c
117 }
118
119 func fp(p *int, o int) *int {
120 checkorder(o)
121 return p
122 }
123
124 func fn(n, o int) int {
125 checkorder(o)
126 return n
127 }
128
129 func die(x int) {
130 println("have", x, "want", n)
131 panic("chan")
132 }
133
134 func main() {
135 // everything happens in init funcs
136 }
137 `
138
139 func parse(name, s string) *template.Template {
140 t, err := template.New(name).Parse(s)
141 if err != nil {
142 panic(fmt.Sprintf("%q: %s", name, err))
143 }
144 return t
145 }
146
147 var recv = parse("recv", `
148 {{/* Send n, receive it one way or another into x, check that they match. */}}
149 c <- n
150 {{if .Maybe}}
151 x = <-c
152 {{else}}
153 select {
154 {{/* Blocking or non-blocking, before the receive. */}}
155 {{/* The compiler implements two-case select where one is default with custom code, */}}
156 {{/* so test the default branch both before and after the send. */}}
157 {{if .MaybeDefault}}
158 default:
159 panic("nonblock")
160 {{end}}
161 {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
162 {{if .Maybe}}
163 case x = <-c:
164 {{else}}{{if .Maybe}}
165 case *f(&x) = <-c:
166 {{else}}{{if .Maybe}}
167 case y := <-c:
168 x = y
169 {{else}}{{if .Maybe}}
170 case i = <-c:
171 x = i.(int)
172 {{else}}
173 case m[13] = <-c:
174 x = m[13]
175 {{end}}{{end}}{{end}}{{end}}
176 {{/* Blocking or non-blocking again, after the receive. */}}
177 {{if .MaybeDefault}}
178 default:
179 panic("nonblock")
180 {{end}}
181 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
182 {{if .Maybe}}
183 case dummy <- 1:
184 panic("dummy send")
185 {{end}}
186 {{if .Maybe}}
187 case <-dummy:
188 panic("dummy receive")
189 {{end}}
190 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
191 {{if .Maybe}}
192 case nilch <- 1:
193 panic("nilch send")
194 {{end}}
195 {{if .Maybe}}
196 case <-nilch:
197 panic("nilch recv")
198 {{end}}
199 }
200 {{end}}
201 if x != n {
202 die(x)
203 }
204 n++
205 `)
206
207 var recvOrder = parse("recvOrder", `
208 {{/* Send n, receive it one way or another into x, check that they match. */}}
209 {{/* Check order of operations along the way by calling functions that check */}}
210 {{/* that the argument sequence is strictly increasing. */}}
211 order = 0
212 c <- n
213 {{if .Maybe}}
214 {{/* Outside of select, left-to-right rule applies. */}}
215 {{/* (Inside select, assignment waits until case is chosen, */}}
216 {{/* so right hand side happens before anything on left hand side. */}}
217 *fp(&x, 1) = <-fc(c, 2)
218 {{else}}{{if .Maybe}}
219 m[fn(13, 1)] = <-fc(c, 2)
220 x = m[13]
221 {{else}}
222 select {
223 {{/* Blocking or non-blocking, before the receive. */}}
224 {{/* The compiler implements two-case select where one is default with custom code, */}}
225 {{/* so test the default branch both before and after the send. */}}
226 {{if .MaybeDefault}}
227 default:
228 panic("nonblock")
229 {{end}}
230 {{/* Receive from c. Different cases are direct, indirect, :=, interface, and map assignment. */}}
231 {{if .Maybe}}
232 case *fp(&x, 100) = <-fc(c, 1):
233 {{else}}{{if .Maybe}}
234 case y := <-fc(c, 1):
235 x = y
236 {{else}}{{if .Maybe}}
237 case i = <-fc(c, 1):
238 x = i.(int)
239 {{else}}
240 case m[fn(13, 100)] = <-fc(c, 1):
241 x = m[13]
242 {{end}}{{end}}{{end}}
243 {{/* Blocking or non-blocking again, after the receive. */}}
244 {{if .MaybeDefault}}
245 default:
246 panic("nonblock")
247 {{end}}
248 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
249 {{if .Maybe}}
250 case fc(dummy, 2) <- fn(1, 3):
251 panic("dummy send")
252 {{end}}
253 {{if .Maybe}}
254 case <-fc(dummy, 4):
255 panic("dummy receive")
256 {{end}}
257 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
258 {{if .Maybe}}
259 case fc(nilch, 5) <- fn(1, 6):
260 panic("nilch send")
261 {{end}}
262 {{if .Maybe}}
263 case <-fc(nilch, 7):
264 panic("nilch recv")
265 {{end}}
266 }
267 {{end}}{{end}}
268 if x != n {
269 die(x)
270 }
271 n++
272 `)
273
274 var send = parse("send", `
275 {{/* Send n one way or another, receive it into x, check that they match. */}}
276 {{if .Maybe}}
277 c <- n
278 {{else}}
279 select {
280 {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
281 {{if .MaybeDefault}}
282 default:
283 panic("nonblock")
284 {{end}}
285 {{/* Send c <- n. No real special cases here, because no values come back */}}
286 {{/* from the send operation. */}}
287 case c <- n:
288 {{/* Blocking or non-blocking. */}}
289 {{if .MaybeDefault}}
290 default:
291 panic("nonblock")
292 {{end}}
293 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
294 {{if .Maybe}}
295 case dummy <- 1:
296 panic("dummy send")
297 {{end}}
298 {{if .Maybe}}
299 case <-dummy:
300 panic("dummy receive")
301 {{end}}
302 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
303 {{if .Maybe}}
304 case nilch <- 1:
305 panic("nilch send")
306 {{end}}
307 {{if .Maybe}}
308 case <-nilch:
309 panic("nilch recv")
310 {{end}}
311 }
312 {{end}}
313 x = <-c
314 if x != n {
315 die(x)
316 }
317 n++
318 `)
319
320 var sendOrder = parse("sendOrder", `
321 {{/* Send n one way or another, receive it into x, check that they match. */}}
322 {{/* Check order of operations along the way by calling functions that check */}}
323 {{/* that the argument sequence is strictly increasing. */}}
324 order = 0
325 {{if .Maybe}}
326 fc(c, 1) <- fn(n, 2)
327 {{else}}
328 select {
329 {{/* Blocking or non-blocking, before the receive (same reason as in recv). */}}
330 {{if .MaybeDefault}}
331 default:
332 panic("nonblock")
333 {{end}}
334 {{/* Send c <- n. No real special cases here, because no values come back */}}
335 {{/* from the send operation. */}}
336 case fc(c, 1) <- fn(n, 2):
337 {{/* Blocking or non-blocking. */}}
338 {{if .MaybeDefault}}
339 default:
340 panic("nonblock")
341 {{end}}
342 {{/* Dummy send, receive to keep compiler from optimizing select. */}}
343 {{if .Maybe}}
344 case fc(dummy, 3) <- fn(1, 4):
345 panic("dummy send")
346 {{end}}
347 {{if .Maybe}}
348 case <-fc(dummy, 5):
349 panic("dummy receive")
350 {{end}}
351 {{/* Nil channel send, receive to keep compiler from optimizing select. */}}
352 {{if .Maybe}}
353 case fc(nilch, 6) <- fn(1, 7):
354 panic("nilch send")
355 {{end}}
356 {{if .Maybe}}
357 case <-fc(nilch, 8):
358 panic("nilch recv")
359 {{end}}
360 }
361 {{end}}
362 x = <-c
363 if x != n {
364 die(x)
365 }
366 n++
367 `)
368
369 var nonblock = parse("nonblock", `
370 x = n
371 {{/* Test various combinations of non-blocking operations. */}}
372 {{/* Receive assignments must not edit or even attempt to compute the address of the lhs. */}}
373 select {
374 {{if .MaybeDefault}}
375 default:
376 {{end}}
377 {{if .Maybe}}
378 case dummy <- 1:
379 panic("dummy <- 1")
380 {{end}}
381 {{if .Maybe}}
382 case nilch <- 1:
383 panic("nilch <- 1")
384 {{end}}
385 {{if .Maybe}}
386 case <-dummy:
387 panic("<-dummy")
388 {{end}}
389 {{if .Maybe}}
390 case x = <-dummy:
391 panic("<-dummy x")
392 {{end}}
393 {{if .Maybe}}
394 case **(**int)(nil) = <-dummy:
395 panic("<-dummy (and didn't crash saving result!)")
396 {{end}}
397 {{if .Maybe}}
398 case <-nilch:
399 panic("<-nilch")
400 {{end}}
401 {{if .Maybe}}
402 case x = <-nilch:
403 panic("<-nilch x")
404 {{end}}
405 {{if .Maybe}}
406 case **(**int)(nil) = <-nilch:
407 panic("<-nilch (and didn't crash saving result!)")
408 {{end}}
409 {{if .MustDefault}}
410 default:
411 {{end}}
412 }
413 if x != n {
414 die(x)
415 }
416 n++
417 `)
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434 type choice struct {
435 i, n int
436 }
437
438 var choices []choice
439 var cp int = -1
440
441 func maybe() bool {
442 return choose(2) == 0
443 }
444
445 func choose(n int) int {
446 if cp >= len(choices) {
447
448 choices = append(choices, choice{0, n})
449 cp = len(choices)
450 return 0
451 }
452
453 if n != choices[cp].n {
454 panic("inconsistent choices")
455 }
456 i := choices[cp].i
457 cp++
458 return i
459 }
460
461 func next() bool {
462 if cp < 0 {
463
464 cp = 0
465 return true
466 }
467
468
469 cp = len(choices) - 1
470 for cp >= 0 && choices[cp].i == choices[cp].n-1 {
471 cp--
472 }
473 if cp < 0 {
474 choices = choices[:0]
475 return false
476 }
477 choices[cp].i++
478 choices = choices[:cp+1]
479 cp = 0
480 return true
481 }
482
View as plain text