v4 / vlib / sync / many_times_test.v
93 lines · 79 sloc · 1.93 KB · df24ab237ef04ddaf535d9b7253cfa8773771816
Raw
1// vtest build: !windows && (amd64 || arm64)
2import sync
3import time
4
5struct Counter {
6pub mut:
7 i int
8}
9
10fn (mut c Counter) add(i int) {
11 c.i = c.i + i
12}
13
14fn run(mut m sync.ManyTimes, mut co Counter, c chan bool) {
15 m.do(fn [mut co] () {
16 co.add(5)
17 })
18 c <- true
19}
20
21fn test_many_times_once() {
22 mut co := &Counter{}
23 mut m := sync.new_many_times(1)
24 c := chan bool{}
25 n := 10
26
27 // It is executed 10 times, but only once actually.
28 for i := 0; i < n; i++ {
29 spawn run(mut m, mut co, c)
30 }
31 for i := 0; i < n; i++ {
32 <-c
33 }
34 assert co.i == 5
35}
36
37fn test_many_times_fifth() {
38 mut co := &Counter{}
39 mut m := sync.new_many_times(5)
40 c := chan bool{}
41 n := 10
42
43 // It is executed 10 times, but only 5 times actually.
44 for i := 0; i < n; i++ {
45 spawn run(mut m, mut co, c)
46 }
47 for i := 0; i < n; i++ {
48 <-c
49 }
50 assert co.i == 25
51}
52
53// Ordering test: do must not return until f() has completed.
54// The bug was that count was stored *before* f() ran, so a concurrent
55// caller could observe count >= times and return on the fast path while
56// f() was still executing.
57
58struct ManyTimesState {
59pub mut:
60 value int
61 ready chan bool
62}
63
64fn run_mt_ordering(mut m sync.ManyTimes, s &ManyTimesState, c chan bool) {
65 m.do(fn [s] () {
66 mut ms := unsafe { &ManyTimesState(s) }
67 ms.ready <- true
68 time.sleep(50 * time.millisecond)
69 ms.value = 99
70 })
71 c <- true
72}
73
74fn test_many_times_ordering() {
75 s := &ManyTimesState{
76 ready: chan bool{cap: 1}
77 }
78 mut m := sync.new_many_times(1)
79 c := chan bool{}
80
81 spawn run_mt_ordering(mut m, s, c)
82
83 // Wait until the goroutine is inside f(). With the old buggy code,
84 // count is incremented before f() runs, so the second do() call sees
85 // count >= times on the fast path and returns immediately — before
86 // f() has finished. With the fix, count is still 0 here, so the
87 // second do() blocks on the mutex until f() completes.
88 _ := <-s.ready
89 m.do(fn () {})
90
91 assert s.value == 99, 'do must not return before f() completes'
92 _ := <-c
93}
94