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