github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/internal/atomic/atomic_test.go (about) 1 // Copyright 2015 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 atomic_test 6 7 import ( 8 "runtime" 9 "runtime/internal/atomic" 10 "runtime/internal/sys" 11 "testing" 12 "unsafe" 13 ) 14 15 func runParallel(N, iter int, f func()) { 16 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(int(N))) 17 done := make(chan bool) 18 for i := 0; i < N; i++ { 19 go func() { 20 for j := 0; j < iter; j++ { 21 f() 22 } 23 done <- true 24 }() 25 } 26 for i := 0; i < N; i++ { 27 <-done 28 } 29 } 30 31 func TestXadduintptr(t *testing.T) { 32 N := 20 33 iter := 100000 34 if testing.Short() { 35 N = 10 36 iter = 10000 37 } 38 inc := uintptr(100) 39 total := uintptr(0) 40 runParallel(N, iter, func() { 41 atomic.Xadduintptr(&total, inc) 42 }) 43 if want := uintptr(N*iter) * inc; want != total { 44 t.Fatalf("xadduintpr error, want %d, got %d", want, total) 45 } 46 total = 0 47 runParallel(N, iter, func() { 48 atomic.Xadduintptr(&total, inc) 49 atomic.Xadduintptr(&total, uintptr(-int64(inc))) 50 }) 51 if total != 0 { 52 t.Fatalf("xadduintpr total error, want %d, got %d", 0, total) 53 } 54 } 55 56 // Tests that xadduintptr correctly updates 64-bit values. The place where 57 // we actually do so is mstats.go, functions mSysStat{Inc,Dec}. 58 func TestXadduintptrOnUint64(t *testing.T) { 59 if sys.BigEndian { 60 // On big endian architectures, we never use xadduintptr to update 61 // 64-bit values and hence we skip the test. (Note that functions 62 // mSysStat{Inc,Dec} in mstats.go have explicit checks for 63 // big-endianness.) 64 t.Skip("skip xadduintptr on big endian architecture") 65 } 66 const inc = 100 67 val := uint64(0) 68 atomic.Xadduintptr((*uintptr)(unsafe.Pointer(&val)), inc) 69 if inc != val { 70 t.Fatalf("xadduintptr should increase lower-order bits, want %d, got %d", inc, val) 71 } 72 } 73 74 func shouldPanic(t *testing.T, name string, f func()) { 75 defer func() { 76 // Check that all GC maps are sane. 77 runtime.GC() 78 79 err := recover() 80 want := "unaligned 64-bit atomic operation" 81 if err == nil { 82 t.Errorf("%s did not panic", name) 83 } else if s, _ := err.(string); s != want { 84 t.Errorf("%s: wanted panic %q, got %q", name, want, err) 85 } 86 }() 87 f() 88 } 89 90 // Variant of sync/atomic's TestUnaligned64: 91 func TestUnaligned64(t *testing.T) { 92 // Unaligned 64-bit atomics on 32-bit systems are 93 // a continual source of pain. Test that on 32-bit systems they crash 94 // instead of failing silently. 95 96 if unsafe.Sizeof(int(0)) != 4 { 97 t.Skip("test only runs on 32-bit systems") 98 } 99 100 x := make([]uint32, 4) 101 u := unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) | 4) // force alignment to 4 102 103 up64 := (*uint64)(u) // misaligned 104 p64 := (*int64)(u) // misaligned 105 106 shouldPanic(t, "Load64", func() { atomic.Load64(up64) }) 107 shouldPanic(t, "Loadint64", func() { atomic.Loadint64(p64) }) 108 shouldPanic(t, "Store64", func() { atomic.Store64(up64, 0) }) 109 shouldPanic(t, "Xadd64", func() { atomic.Xadd64(up64, 1) }) 110 shouldPanic(t, "Xchg64", func() { atomic.Xchg64(up64, 1) }) 111 shouldPanic(t, "Cas64", func() { atomic.Cas64(up64, 1, 2) }) 112 } 113 114 func TestAnd8(t *testing.T) { 115 // Basic sanity check. 116 x := uint8(0xff) 117 for i := uint8(0); i < 8; i++ { 118 atomic.And8(&x, ^(1 << i)) 119 if r := uint8(0xff) << (i + 1); x != r { 120 t.Fatalf("clearing bit %#x: want %#x, got %#x", uint8(1<<i), r, x) 121 } 122 } 123 124 // Set every bit in array to 1. 125 a := make([]uint8, 1<<12) 126 for i := range a { 127 a[i] = 0xff 128 } 129 130 // Clear array bit-by-bit in different goroutines. 131 done := make(chan bool) 132 for i := 0; i < 8; i++ { 133 m := ^uint8(1 << i) 134 go func() { 135 for i := range a { 136 atomic.And8(&a[i], m) 137 } 138 done <- true 139 }() 140 } 141 for i := 0; i < 8; i++ { 142 <-done 143 } 144 145 // Check that the array has been totally cleared. 146 for i, v := range a { 147 if v != 0 { 148 t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint8(0), v) 149 } 150 } 151 } 152 153 func TestAnd(t *testing.T) { 154 // Basic sanity check. 155 x := uint32(0xffffffff) 156 for i := uint32(0); i < 32; i++ { 157 atomic.And(&x, ^(1 << i)) 158 if r := uint32(0xffffffff) << (i + 1); x != r { 159 t.Fatalf("clearing bit %#x: want %#x, got %#x", uint32(1<<i), r, x) 160 } 161 } 162 163 // Set every bit in array to 1. 164 a := make([]uint32, 1<<12) 165 for i := range a { 166 a[i] = 0xffffffff 167 } 168 169 // Clear array bit-by-bit in different goroutines. 170 done := make(chan bool) 171 for i := 0; i < 32; i++ { 172 m := ^uint32(1 << i) 173 go func() { 174 for i := range a { 175 atomic.And(&a[i], m) 176 } 177 done <- true 178 }() 179 } 180 for i := 0; i < 32; i++ { 181 <-done 182 } 183 184 // Check that the array has been totally cleared. 185 for i, v := range a { 186 if v != 0 { 187 t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint32(0), v) 188 } 189 } 190 } 191 192 func TestOr8(t *testing.T) { 193 // Basic sanity check. 194 x := uint8(0) 195 for i := uint8(0); i < 8; i++ { 196 atomic.Or8(&x, 1<<i) 197 if r := (uint8(1) << (i + 1)) - 1; x != r { 198 t.Fatalf("setting bit %#x: want %#x, got %#x", uint8(1)<<i, r, x) 199 } 200 } 201 202 // Start with every bit in array set to 0. 203 a := make([]uint8, 1<<12) 204 205 // Set every bit in array bit-by-bit in different goroutines. 206 done := make(chan bool) 207 for i := 0; i < 8; i++ { 208 m := uint8(1 << i) 209 go func() { 210 for i := range a { 211 atomic.Or8(&a[i], m) 212 } 213 done <- true 214 }() 215 } 216 for i := 0; i < 8; i++ { 217 <-done 218 } 219 220 // Check that the array has been totally set. 221 for i, v := range a { 222 if v != 0xff { 223 t.Fatalf("a[%v] not fully set: want %#x, got %#x", i, uint8(0xff), v) 224 } 225 } 226 } 227 228 func TestOr(t *testing.T) { 229 // Basic sanity check. 230 x := uint32(0) 231 for i := uint32(0); i < 32; i++ { 232 atomic.Or(&x, 1<<i) 233 if r := (uint32(1) << (i + 1)) - 1; x != r { 234 t.Fatalf("setting bit %#x: want %#x, got %#x", uint32(1)<<i, r, x) 235 } 236 } 237 238 // Start with every bit in array set to 0. 239 a := make([]uint32, 1<<12) 240 241 // Set every bit in array bit-by-bit in different goroutines. 242 done := make(chan bool) 243 for i := 0; i < 32; i++ { 244 m := uint32(1 << i) 245 go func() { 246 for i := range a { 247 atomic.Or(&a[i], m) 248 } 249 done <- true 250 }() 251 } 252 for i := 0; i < 32; i++ { 253 <-done 254 } 255 256 // Check that the array has been totally set. 257 for i, v := range a { 258 if v != 0xffffffff { 259 t.Fatalf("a[%v] not fully set: want %#x, got %#x", i, uint32(0xffffffff), v) 260 } 261 } 262 } 263 264 func TestBitwiseContended8(t *testing.T) { 265 // Start with every bit in array set to 0. 266 a := make([]uint8, 16) 267 268 // Iterations to try. 269 N := 1 << 16 270 if testing.Short() { 271 N = 1 << 10 272 } 273 274 // Set and then clear every bit in the array bit-by-bit in different goroutines. 275 done := make(chan bool) 276 for i := 0; i < 8; i++ { 277 m := uint8(1 << i) 278 go func() { 279 for n := 0; n < N; n++ { 280 for i := range a { 281 atomic.Or8(&a[i], m) 282 if atomic.Load8(&a[i])&m != m { 283 t.Errorf("a[%v] bit %#x not set", i, m) 284 } 285 atomic.And8(&a[i], ^m) 286 if atomic.Load8(&a[i])&m != 0 { 287 t.Errorf("a[%v] bit %#x not clear", i, m) 288 } 289 } 290 } 291 done <- true 292 }() 293 } 294 for i := 0; i < 8; i++ { 295 <-done 296 } 297 298 // Check that the array has been totally cleared. 299 for i, v := range a { 300 if v != 0 { 301 t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint8(0), v) 302 } 303 } 304 } 305 306 func TestBitwiseContended(t *testing.T) { 307 // Start with every bit in array set to 0. 308 a := make([]uint32, 16) 309 310 // Iterations to try. 311 N := 1 << 16 312 if testing.Short() { 313 N = 1 << 10 314 } 315 316 // Set and then clear every bit in the array bit-by-bit in different goroutines. 317 done := make(chan bool) 318 for i := 0; i < 32; i++ { 319 m := uint32(1 << i) 320 go func() { 321 for n := 0; n < N; n++ { 322 for i := range a { 323 atomic.Or(&a[i], m) 324 if atomic.Load(&a[i])&m != m { 325 t.Errorf("a[%v] bit %#x not set", i, m) 326 } 327 atomic.And(&a[i], ^m) 328 if atomic.Load(&a[i])&m != 0 { 329 t.Errorf("a[%v] bit %#x not clear", i, m) 330 } 331 } 332 } 333 done <- true 334 }() 335 } 336 for i := 0; i < 32; i++ { 337 <-done 338 } 339 340 // Check that the array has been totally cleared. 341 for i, v := range a { 342 if v != 0 { 343 t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint32(0), v) 344 } 345 } 346 } 347 348 func TestStorepNoWB(t *testing.T) { 349 var p [2]*int 350 for i := range p { 351 atomic.StorepNoWB(unsafe.Pointer(&p[i]), unsafe.Pointer(new(int))) 352 } 353 if p[0] == p[1] { 354 t.Error("Bad escape analysis of StorepNoWB") 355 } 356 }