Home | History | Annotate | Download | only in testdata
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package race_test
      6 
      7 import (
      8 	"runtime"
      9 	"sync"
     10 	"testing"
     11 	"time"
     12 )
     13 
     14 func TestNoRaceWaitGroup(t *testing.T) {
     15 	var x int
     16 	var wg sync.WaitGroup
     17 	n := 1
     18 	for i := 0; i < n; i++ {
     19 		wg.Add(1)
     20 		j := i
     21 		go func() {
     22 			x = j
     23 			wg.Done()
     24 		}()
     25 	}
     26 	wg.Wait()
     27 }
     28 
     29 func TestRaceWaitGroup(t *testing.T) {
     30 	var x int
     31 	var wg sync.WaitGroup
     32 	n := 2
     33 	for i := 0; i < n; i++ {
     34 		wg.Add(1)
     35 		j := i
     36 		go func() {
     37 			x = j
     38 			wg.Done()
     39 		}()
     40 	}
     41 	wg.Wait()
     42 }
     43 
     44 func TestNoRaceWaitGroup2(t *testing.T) {
     45 	var x int
     46 	var wg sync.WaitGroup
     47 	wg.Add(1)
     48 	go func() {
     49 		x = 1
     50 		wg.Done()
     51 	}()
     52 	wg.Wait()
     53 	x = 2
     54 }
     55 
     56 // incrementing counter in Add and locking wg's mutex
     57 func TestRaceWaitGroupAsMutex(t *testing.T) {
     58 	var x int
     59 	var wg sync.WaitGroup
     60 	c := make(chan bool, 2)
     61 	go func() {
     62 		wg.Wait()
     63 		time.Sleep(100 * time.Millisecond)
     64 		wg.Add(+1)
     65 		x = 1
     66 		wg.Add(-1)
     67 		c <- true
     68 	}()
     69 	go func() {
     70 		wg.Wait()
     71 		time.Sleep(100 * time.Millisecond)
     72 		wg.Add(+1)
     73 		x = 2
     74 		wg.Add(-1)
     75 		c <- true
     76 	}()
     77 	<-c
     78 	<-c
     79 }
     80 
     81 // Incorrect usage: Add is too late.
     82 func TestRaceWaitGroupWrongWait(t *testing.T) {
     83 	c := make(chan bool, 2)
     84 	var x int
     85 	var wg sync.WaitGroup
     86 	go func() {
     87 		wg.Add(1)
     88 		runtime.Gosched()
     89 		x = 1
     90 		wg.Done()
     91 		c <- true
     92 	}()
     93 	go func() {
     94 		wg.Add(1)
     95 		runtime.Gosched()
     96 		x = 2
     97 		wg.Done()
     98 		c <- true
     99 	}()
    100 	wg.Wait()
    101 	<-c
    102 	<-c
    103 }
    104 
    105 func TestRaceWaitGroupWrongAdd(t *testing.T) {
    106 	c := make(chan bool, 2)
    107 	var wg sync.WaitGroup
    108 	go func() {
    109 		wg.Add(1)
    110 		time.Sleep(100 * time.Millisecond)
    111 		wg.Done()
    112 		c <- true
    113 	}()
    114 	go func() {
    115 		wg.Add(1)
    116 		time.Sleep(100 * time.Millisecond)
    117 		wg.Done()
    118 		c <- true
    119 	}()
    120 	time.Sleep(50 * time.Millisecond)
    121 	wg.Wait()
    122 	<-c
    123 	<-c
    124 }
    125 
    126 func TestNoRaceWaitGroupMultipleWait(t *testing.T) {
    127 	c := make(chan bool, 2)
    128 	var wg sync.WaitGroup
    129 	go func() {
    130 		wg.Wait()
    131 		c <- true
    132 	}()
    133 	go func() {
    134 		wg.Wait()
    135 		c <- true
    136 	}()
    137 	wg.Wait()
    138 	<-c
    139 	<-c
    140 }
    141 
    142 func TestNoRaceWaitGroupMultipleWait2(t *testing.T) {
    143 	c := make(chan bool, 2)
    144 	var wg sync.WaitGroup
    145 	wg.Add(2)
    146 	go func() {
    147 		wg.Done()
    148 		wg.Wait()
    149 		c <- true
    150 	}()
    151 	go func() {
    152 		wg.Done()
    153 		wg.Wait()
    154 		c <- true
    155 	}()
    156 	wg.Wait()
    157 	<-c
    158 	<-c
    159 }
    160 
    161 func TestNoRaceWaitGroupMultipleWait3(t *testing.T) {
    162 	const P = 3
    163 	var data [P]int
    164 	done := make(chan bool, P)
    165 	var wg sync.WaitGroup
    166 	wg.Add(P)
    167 	for p := 0; p < P; p++ {
    168 		go func(p int) {
    169 			data[p] = 42
    170 			wg.Done()
    171 		}(p)
    172 	}
    173 	for p := 0; p < P; p++ {
    174 		go func() {
    175 			wg.Wait()
    176 			for p1 := 0; p1 < P; p1++ {
    177 				_ = data[p1]
    178 			}
    179 			done <- true
    180 		}()
    181 	}
    182 	for p := 0; p < P; p++ {
    183 		<-done
    184 	}
    185 }
    186 
    187 // Correct usage but still a race
    188 func TestRaceWaitGroup2(t *testing.T) {
    189 	var x int
    190 	var wg sync.WaitGroup
    191 	wg.Add(2)
    192 	go func() {
    193 		x = 1
    194 		wg.Done()
    195 	}()
    196 	go func() {
    197 		x = 2
    198 		wg.Done()
    199 	}()
    200 	wg.Wait()
    201 }
    202 
    203 func TestNoRaceWaitGroupPanicRecover(t *testing.T) {
    204 	var x int
    205 	var wg sync.WaitGroup
    206 	defer func() {
    207 		err := recover()
    208 		if err != "sync: negative WaitGroup counter" {
    209 			t.Fatalf("Unexpected panic: %#v", err)
    210 		}
    211 		x = 2
    212 	}()
    213 	x = 1
    214 	wg.Add(-1)
    215 }
    216 
    217 // TODO: this is actually a panic-synchronization test, not a
    218 // WaitGroup test. Move it to another *_test file
    219 // Is it possible to get a race by synchronization via panic?
    220 func TestNoRaceWaitGroupPanicRecover2(t *testing.T) {
    221 	var x int
    222 	var wg sync.WaitGroup
    223 	ch := make(chan bool, 1)
    224 	var f func() = func() {
    225 		x = 2
    226 		ch <- true
    227 	}
    228 	go func() {
    229 		defer func() {
    230 			err := recover()
    231 			if err != "sync: negative WaitGroup counter" {
    232 			}
    233 			go f()
    234 		}()
    235 		x = 1
    236 		wg.Add(-1)
    237 	}()
    238 
    239 	<-ch
    240 }
    241 
    242 func TestNoRaceWaitGroupTransitive(t *testing.T) {
    243 	x, y := 0, 0
    244 	var wg sync.WaitGroup
    245 	wg.Add(2)
    246 	go func() {
    247 		x = 42
    248 		wg.Done()
    249 	}()
    250 	go func() {
    251 		time.Sleep(1e7)
    252 		y = 42
    253 		wg.Done()
    254 	}()
    255 	wg.Wait()
    256 	_ = x
    257 	_ = y
    258 }
    259 
    260 func TestNoRaceWaitGroupReuse(t *testing.T) {
    261 	const P = 3
    262 	var data [P]int
    263 	var wg sync.WaitGroup
    264 	for try := 0; try < 3; try++ {
    265 		wg.Add(P)
    266 		for p := 0; p < P; p++ {
    267 			go func(p int) {
    268 				data[p]++
    269 				wg.Done()
    270 			}(p)
    271 		}
    272 		wg.Wait()
    273 		for p := 0; p < P; p++ {
    274 			data[p]++
    275 		}
    276 	}
    277 }
    278 
    279 func TestNoRaceWaitGroupReuse2(t *testing.T) {
    280 	const P = 3
    281 	var data [P]int
    282 	var wg sync.WaitGroup
    283 	for try := 0; try < 3; try++ {
    284 		wg.Add(P)
    285 		for p := 0; p < P; p++ {
    286 			go func(p int) {
    287 				data[p]++
    288 				wg.Done()
    289 			}(p)
    290 		}
    291 		done := make(chan bool)
    292 		go func() {
    293 			wg.Wait()
    294 			for p := 0; p < P; p++ {
    295 				data[p]++
    296 			}
    297 			done <- true
    298 		}()
    299 		wg.Wait()
    300 		<-done
    301 		for p := 0; p < P; p++ {
    302 			data[p]++
    303 		}
    304 	}
    305 }
    306 
    307 func TestRaceWaitGroupReuse(t *testing.T) {
    308 	const P = 3
    309 	const T = 3
    310 	done := make(chan bool, T)
    311 	var wg sync.WaitGroup
    312 	for try := 0; try < T; try++ {
    313 		var data [P]int
    314 		wg.Add(P)
    315 		for p := 0; p < P; p++ {
    316 			go func(p int) {
    317 				time.Sleep(50 * time.Millisecond)
    318 				data[p]++
    319 				wg.Done()
    320 			}(p)
    321 		}
    322 		go func() {
    323 			wg.Wait()
    324 			for p := 0; p < P; p++ {
    325 				data[p]++
    326 			}
    327 			done <- true
    328 		}()
    329 		time.Sleep(100 * time.Millisecond)
    330 		wg.Wait()
    331 	}
    332 	for try := 0; try < T; try++ {
    333 		<-done
    334 	}
    335 }
    336 
    337 func TestNoRaceWaitGroupConcurrentAdd(t *testing.T) {
    338 	const P = 4
    339 	waiting := make(chan bool, P)
    340 	var wg sync.WaitGroup
    341 	for p := 0; p < P; p++ {
    342 		go func() {
    343 			wg.Add(1)
    344 			waiting <- true
    345 			wg.Done()
    346 		}()
    347 	}
    348 	for p := 0; p < P; p++ {
    349 		<-waiting
    350 	}
    351 	wg.Wait()
    352 }
    353