github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/atomicbitops/atomicbitops_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package atomicbitops 16 17 import ( 18 "runtime" 19 "testing" 20 21 "github.com/SagerNet/gvisor/pkg/sync" 22 ) 23 24 const iterations = 100 25 26 func detectRaces32(val, target uint32, fn func(*uint32, uint32)) bool { 27 runtime.GOMAXPROCS(100) 28 for n := 0; n < iterations; n++ { 29 x := val 30 var wg sync.WaitGroup 31 for i := uint32(0); i < 32; i++ { 32 wg.Add(1) 33 go func(a *uint32, i uint32) { 34 defer wg.Done() 35 fn(a, uint32(1<<i)) 36 }(&x, i) 37 } 38 wg.Wait() 39 if x != target { 40 return true 41 } 42 } 43 return false 44 } 45 46 func detectRaces64(val, target uint64, fn func(*uint64, uint64)) bool { 47 runtime.GOMAXPROCS(100) 48 for n := 0; n < iterations; n++ { 49 x := val 50 var wg sync.WaitGroup 51 for i := uint64(0); i < 64; i++ { 52 wg.Add(1) 53 go func(a *uint64, i uint64) { 54 defer wg.Done() 55 fn(a, uint64(1<<i)) 56 }(&x, i) 57 } 58 wg.Wait() 59 if x != target { 60 return true 61 } 62 } 63 return false 64 } 65 66 func TestOrUint32(t *testing.T) { 67 if detectRaces32(0x0, 0xffffffff, OrUint32) { 68 t.Error("Data race detected!") 69 } 70 } 71 72 func TestAndUint32(t *testing.T) { 73 if detectRaces32(0xf0f0f0f0, 0x00000000, AndUint32) { 74 t.Error("Data race detected!") 75 } 76 } 77 78 func TestXorUint32(t *testing.T) { 79 if detectRaces32(0xf0f0f0f0, 0x0f0f0f0f, XorUint32) { 80 t.Error("Data race detected!") 81 } 82 } 83 84 func TestOrUint64(t *testing.T) { 85 if detectRaces64(0x0, 0xffffffffffffffff, OrUint64) { 86 t.Error("Data race detected!") 87 } 88 } 89 90 func TestAndUint64(t *testing.T) { 91 if detectRaces64(0xf0f0f0f0f0f0f0f0, 0x0, AndUint64) { 92 t.Error("Data race detected!") 93 } 94 } 95 96 func TestXorUint64(t *testing.T) { 97 if detectRaces64(0xf0f0f0f0f0f0f0f0, 0x0f0f0f0f0f0f0f0f, XorUint64) { 98 t.Error("Data race detected!") 99 } 100 } 101 102 func TestCompareAndSwapUint32(t *testing.T) { 103 tests := []struct { 104 name string 105 prev uint32 106 old uint32 107 new uint32 108 next uint32 109 }{ 110 { 111 name: "Successful compare-and-swap with prev == new", 112 prev: 10, 113 old: 10, 114 new: 10, 115 next: 10, 116 }, 117 { 118 name: "Successful compare-and-swap with prev != new", 119 prev: 20, 120 old: 20, 121 new: 22, 122 next: 22, 123 }, 124 { 125 name: "Failed compare-and-swap with prev == new", 126 prev: 31, 127 old: 30, 128 new: 31, 129 next: 31, 130 }, 131 { 132 name: "Failed compare-and-swap with prev != new", 133 prev: 41, 134 old: 40, 135 new: 42, 136 next: 41, 137 }, 138 } 139 for _, test := range tests { 140 val := test.prev 141 prev := CompareAndSwapUint32(&val, test.old, test.new) 142 if got, want := prev, test.prev; got != want { 143 t.Errorf("%s: incorrect returned previous value: got %d, expected %d", test.name, got, want) 144 } 145 if got, want := val, test.next; got != want { 146 t.Errorf("%s: incorrect value stored in val: got %d, expected %d", test.name, got, want) 147 } 148 } 149 } 150 151 func TestCompareAndSwapUint64(t *testing.T) { 152 tests := []struct { 153 name string 154 prev uint64 155 old uint64 156 new uint64 157 next uint64 158 }{ 159 { 160 name: "Successful compare-and-swap with prev == new", 161 prev: 0x100000000, 162 old: 0x100000000, 163 new: 0x100000000, 164 next: 0x100000000, 165 }, 166 { 167 name: "Successful compare-and-swap with prev != new", 168 prev: 0x200000000, 169 old: 0x200000000, 170 new: 0x200000002, 171 next: 0x200000002, 172 }, 173 { 174 name: "Failed compare-and-swap with prev == new", 175 prev: 0x300000001, 176 old: 0x300000000, 177 new: 0x300000001, 178 next: 0x300000001, 179 }, 180 { 181 name: "Failed compare-and-swap with prev != new", 182 prev: 0x400000001, 183 old: 0x400000000, 184 new: 0x400000002, 185 next: 0x400000001, 186 }, 187 } 188 for _, test := range tests { 189 val := test.prev 190 prev := CompareAndSwapUint64(&val, test.old, test.new) 191 if got, want := prev, test.prev; got != want { 192 t.Errorf("%s: incorrect returned previous value: got %d, expected %d", test.name, got, want) 193 } 194 if got, want := val, test.next; got != want { 195 t.Errorf("%s: incorrect value stored in val: got %d, expected %d", test.name, got, want) 196 } 197 } 198 }