Home | History | Annotate | Download | only in chan
      1 // runoutput
      2 
      3 // Copyright 2011 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 // Generate test of channel operations and simple selects.
      8 // The output of this program is compiled and run to do the
      9 // actual test.
     10 
     11 // Each test does only one real send or receive at a time, but phrased
     12 // in various ways that the compiler may or may not rewrite
     13 // into simpler expressions.
     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 	// Generate each test as a separate function to avoid
     31 	// hitting the gc optimizer with one enormous function.
     32 	// If we name all the functions init we don't have to
     33 	// maintain a list of which ones to run.
     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 // Code for enumerating all possible paths through
    420 // some logic.  The logic should call choose(n) when
    421 // it wants to choose between n possibilities.
    422 // On successive runs through the logic, choose(n)
    423 // will return 0, 1, ..., n-1.  The helper maybe() is
    424 // similar but returns true and then false.
    425 //
    426 // Given a function gen that generates an output
    427 // using choose and maybe, code can generate all
    428 // possible outputs using
    429 //
    430 //	for next() {
    431 //		gen()
    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 		// never asked this before: start with 0.
    448 		choices = append(choices, choice{0, n})
    449 		cp = len(choices)
    450 		return 0
    451 	}
    452 	// otherwise give recorded answer
    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 		// start a new round
    464 		cp = 0
    465 		return true
    466 	}
    467 
    468 	// increment last choice sequence
    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