github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/sync/atomic/atomic_test.go (about) 1 // Copyright 2011 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 "fmt" 9 "runtime" 10 "strings" 11 . "sync/atomic" 12 "testing" 13 "unsafe" 14 ) 15 16 // Tests of correct behavior, without contention. 17 // (Does the function work as advertised?) 18 // 19 // Test that the Add functions add correctly. 20 // Test that the CompareAndSwap functions actually 21 // do the comparison and the swap correctly. 22 // 23 // The loop over power-of-two values is meant to 24 // ensure that the operations apply to the full word size. 25 // The struct fields x.before and x.after check that the 26 // operations do not extend past the full word size. 27 28 const ( 29 magic32 = 0xdedbeef 30 magic64 = 0xdeddeadbeefbeef 31 ) 32 33 // Do the 64-bit functions panic? If so, don't bother testing. 34 var test64err = func() (err interface{}) { 35 defer func() { 36 err = recover() 37 }() 38 var x int64 39 AddInt64(&x, 1) 40 return nil 41 }() 42 43 func TestSwapInt32(t *testing.T) { 44 var x struct { 45 before int32 46 i int32 47 after int32 48 } 49 x.before = magic32 50 x.after = magic32 51 var j int32 52 for delta := int32(1); delta+delta > delta; delta += delta { 53 k := SwapInt32(&x.i, delta) 54 if x.i != delta || k != j { 55 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 56 } 57 j = delta 58 } 59 if x.before != magic32 || x.after != magic32 { 60 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 61 } 62 } 63 64 func TestSwapUint32(t *testing.T) { 65 var x struct { 66 before uint32 67 i uint32 68 after uint32 69 } 70 x.before = magic32 71 x.after = magic32 72 var j uint32 73 for delta := uint32(1); delta+delta > delta; delta += delta { 74 k := SwapUint32(&x.i, delta) 75 if x.i != delta || k != j { 76 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 77 } 78 j = delta 79 } 80 if x.before != magic32 || x.after != magic32 { 81 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 82 } 83 } 84 85 func TestSwapInt64(t *testing.T) { 86 if test64err != nil { 87 t.Skipf("Skipping 64-bit tests: %v", test64err) 88 } 89 var x struct { 90 before int64 91 i int64 92 after int64 93 } 94 x.before = magic64 95 x.after = magic64 96 var j int64 97 for delta := int64(1); delta+delta > delta; delta += delta { 98 k := SwapInt64(&x.i, delta) 99 if x.i != delta || k != j { 100 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 101 } 102 j = delta 103 } 104 if x.before != magic64 || x.after != magic64 { 105 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 106 } 107 } 108 109 func TestSwapUint64(t *testing.T) { 110 if test64err != nil { 111 t.Skipf("Skipping 64-bit tests: %v", test64err) 112 } 113 var x struct { 114 before uint64 115 i uint64 116 after uint64 117 } 118 x.before = magic64 119 x.after = magic64 120 var j uint64 121 for delta := uint64(1); delta+delta > delta; delta += delta { 122 k := SwapUint64(&x.i, delta) 123 if x.i != delta || k != j { 124 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 125 } 126 j = delta 127 } 128 if x.before != magic64 || x.after != magic64 { 129 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 130 } 131 } 132 133 func TestSwapUintptr(t *testing.T) { 134 var x struct { 135 before uintptr 136 i uintptr 137 after uintptr 138 } 139 var m uint64 = magic64 140 magicptr := uintptr(m) 141 x.before = magicptr 142 x.after = magicptr 143 var j uintptr 144 for delta := uintptr(1); delta+delta > delta; delta += delta { 145 k := SwapUintptr(&x.i, delta) 146 if x.i != delta || k != j { 147 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 148 } 149 j = delta 150 } 151 if x.before != magicptr || x.after != magicptr { 152 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 153 } 154 } 155 156 var global [1024]byte 157 158 func testPointers() []unsafe.Pointer { 159 var pointers []unsafe.Pointer 160 // globals 161 for i := 0; i < 10; i++ { 162 pointers = append(pointers, unsafe.Pointer(&global[1<<i-1])) 163 } 164 // heap 165 pointers = append(pointers, unsafe.Pointer(new(byte))) 166 // nil 167 pointers = append(pointers, nil) 168 return pointers 169 } 170 171 func TestSwapPointer(t *testing.T) { 172 var x struct { 173 before uintptr 174 i unsafe.Pointer 175 after uintptr 176 } 177 var m uint64 = magic64 178 magicptr := uintptr(m) 179 x.before = magicptr 180 x.after = magicptr 181 var j unsafe.Pointer 182 183 for _, p := range testPointers() { 184 k := SwapPointer(&x.i, p) 185 if x.i != p || k != j { 186 t.Fatalf("p=%p i=%p j=%p k=%p", p, x.i, j, k) 187 } 188 j = p 189 } 190 if x.before != magicptr || x.after != magicptr { 191 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 192 } 193 } 194 195 func TestAddInt32(t *testing.T) { 196 var x struct { 197 before int32 198 i int32 199 after int32 200 } 201 x.before = magic32 202 x.after = magic32 203 var j int32 204 for delta := int32(1); delta+delta > delta; delta += delta { 205 k := AddInt32(&x.i, delta) 206 j += delta 207 if x.i != j || k != j { 208 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 209 } 210 } 211 if x.before != magic32 || x.after != magic32 { 212 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 213 } 214 } 215 216 func TestAddUint32(t *testing.T) { 217 var x struct { 218 before uint32 219 i uint32 220 after uint32 221 } 222 x.before = magic32 223 x.after = magic32 224 var j uint32 225 for delta := uint32(1); delta+delta > delta; delta += delta { 226 k := AddUint32(&x.i, delta) 227 j += delta 228 if x.i != j || k != j { 229 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 230 } 231 } 232 if x.before != magic32 || x.after != magic32 { 233 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 234 } 235 } 236 237 func TestAddInt64(t *testing.T) { 238 if test64err != nil { 239 t.Skipf("Skipping 64-bit tests: %v", test64err) 240 } 241 var x struct { 242 before int64 243 i int64 244 after int64 245 } 246 x.before = magic64 247 x.after = magic64 248 var j int64 249 for delta := int64(1); delta+delta > delta; delta += delta { 250 k := AddInt64(&x.i, delta) 251 j += delta 252 if x.i != j || k != j { 253 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 254 } 255 } 256 if x.before != magic64 || x.after != magic64 { 257 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, int64(magic64), int64(magic64)) 258 } 259 } 260 261 func TestAddUint64(t *testing.T) { 262 if test64err != nil { 263 t.Skipf("Skipping 64-bit tests: %v", test64err) 264 } 265 var x struct { 266 before uint64 267 i uint64 268 after uint64 269 } 270 x.before = magic64 271 x.after = magic64 272 var j uint64 273 for delta := uint64(1); delta+delta > delta; delta += delta { 274 k := AddUint64(&x.i, delta) 275 j += delta 276 if x.i != j || k != j { 277 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 278 } 279 } 280 if x.before != magic64 || x.after != magic64 { 281 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 282 } 283 } 284 285 func TestAddUintptr(t *testing.T) { 286 var x struct { 287 before uintptr 288 i uintptr 289 after uintptr 290 } 291 var m uint64 = magic64 292 magicptr := uintptr(m) 293 x.before = magicptr 294 x.after = magicptr 295 var j uintptr 296 for delta := uintptr(1); delta+delta > delta; delta += delta { 297 k := AddUintptr(&x.i, delta) 298 j += delta 299 if x.i != j || k != j { 300 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 301 } 302 } 303 if x.before != magicptr || x.after != magicptr { 304 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 305 } 306 } 307 308 func TestCompareAndSwapInt32(t *testing.T) { 309 var x struct { 310 before int32 311 i int32 312 after int32 313 } 314 x.before = magic32 315 x.after = magic32 316 for val := int32(1); val+val > val; val += val { 317 x.i = val 318 if !CompareAndSwapInt32(&x.i, val, val+1) { 319 t.Fatalf("should have swapped %#x %#x", val, val+1) 320 } 321 if x.i != val+1 { 322 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 323 } 324 x.i = val + 1 325 if CompareAndSwapInt32(&x.i, val, val+2) { 326 t.Fatalf("should not have swapped %#x %#x", val, val+2) 327 } 328 if x.i != val+1 { 329 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 330 } 331 } 332 if x.before != magic32 || x.after != magic32 { 333 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 334 } 335 } 336 337 func TestCompareAndSwapUint32(t *testing.T) { 338 var x struct { 339 before uint32 340 i uint32 341 after uint32 342 } 343 x.before = magic32 344 x.after = magic32 345 for val := uint32(1); val+val > val; val += val { 346 x.i = val 347 if !CompareAndSwapUint32(&x.i, val, val+1) { 348 t.Fatalf("should have swapped %#x %#x", val, val+1) 349 } 350 if x.i != val+1 { 351 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 352 } 353 x.i = val + 1 354 if CompareAndSwapUint32(&x.i, val, val+2) { 355 t.Fatalf("should not have swapped %#x %#x", val, val+2) 356 } 357 if x.i != val+1 { 358 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 359 } 360 } 361 if x.before != magic32 || x.after != magic32 { 362 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 363 } 364 } 365 366 func TestCompareAndSwapInt64(t *testing.T) { 367 if test64err != nil { 368 t.Skipf("Skipping 64-bit tests: %v", test64err) 369 } 370 var x struct { 371 before int64 372 i int64 373 after int64 374 } 375 x.before = magic64 376 x.after = magic64 377 for val := int64(1); val+val > val; val += val { 378 x.i = val 379 if !CompareAndSwapInt64(&x.i, val, val+1) { 380 t.Fatalf("should have swapped %#x %#x", val, val+1) 381 } 382 if x.i != val+1 { 383 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 384 } 385 x.i = val + 1 386 if CompareAndSwapInt64(&x.i, val, val+2) { 387 t.Fatalf("should not have swapped %#x %#x", val, val+2) 388 } 389 if x.i != val+1 { 390 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 391 } 392 } 393 if x.before != magic64 || x.after != magic64 { 394 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 395 } 396 } 397 398 func testCompareAndSwapUint64(t *testing.T, cas func(*uint64, uint64, uint64) bool) { 399 if test64err != nil { 400 t.Skipf("Skipping 64-bit tests: %v", test64err) 401 } 402 var x struct { 403 before uint64 404 i uint64 405 after uint64 406 } 407 x.before = magic64 408 x.after = magic64 409 for val := uint64(1); val+val > val; val += val { 410 x.i = val 411 if !cas(&x.i, val, val+1) { 412 t.Fatalf("should have swapped %#x %#x", val, val+1) 413 } 414 if x.i != val+1 { 415 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 416 } 417 x.i = val + 1 418 if cas(&x.i, val, val+2) { 419 t.Fatalf("should not have swapped %#x %#x", val, val+2) 420 } 421 if x.i != val+1 { 422 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 423 } 424 } 425 if x.before != magic64 || x.after != magic64 { 426 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 427 } 428 } 429 430 func TestCompareAndSwapUint64(t *testing.T) { 431 testCompareAndSwapUint64(t, CompareAndSwapUint64) 432 } 433 434 func TestCompareAndSwapUintptr(t *testing.T) { 435 var x struct { 436 before uintptr 437 i uintptr 438 after uintptr 439 } 440 var m uint64 = magic64 441 magicptr := uintptr(m) 442 x.before = magicptr 443 x.after = magicptr 444 for val := uintptr(1); val+val > val; val += val { 445 x.i = val 446 if !CompareAndSwapUintptr(&x.i, val, val+1) { 447 t.Fatalf("should have swapped %#x %#x", val, val+1) 448 } 449 if x.i != val+1 { 450 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 451 } 452 x.i = val + 1 453 if CompareAndSwapUintptr(&x.i, val, val+2) { 454 t.Fatalf("should not have swapped %#x %#x", val, val+2) 455 } 456 if x.i != val+1 { 457 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 458 } 459 } 460 if x.before != magicptr || x.after != magicptr { 461 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 462 } 463 } 464 465 func TestCompareAndSwapPointer(t *testing.T) { 466 var x struct { 467 before uintptr 468 i unsafe.Pointer 469 after uintptr 470 } 471 var m uint64 = magic64 472 magicptr := uintptr(m) 473 x.before = magicptr 474 x.after = magicptr 475 q := unsafe.Pointer(new(byte)) 476 for _, p := range testPointers() { 477 x.i = p 478 if !CompareAndSwapPointer(&x.i, p, q) { 479 t.Fatalf("should have swapped %p %p", p, q) 480 } 481 if x.i != q { 482 t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) 483 } 484 if CompareAndSwapPointer(&x.i, p, nil) { 485 t.Fatalf("should not have swapped %p nil", p) 486 } 487 if x.i != q { 488 t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) 489 } 490 } 491 if x.before != magicptr || x.after != magicptr { 492 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 493 } 494 } 495 496 func TestLoadInt32(t *testing.T) { 497 var x struct { 498 before int32 499 i int32 500 after int32 501 } 502 x.before = magic32 503 x.after = magic32 504 for delta := int32(1); delta+delta > delta; delta += delta { 505 k := LoadInt32(&x.i) 506 if k != x.i { 507 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 508 } 509 x.i += delta 510 } 511 if x.before != magic32 || x.after != magic32 { 512 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 513 } 514 } 515 516 func TestLoadUint32(t *testing.T) { 517 var x struct { 518 before uint32 519 i uint32 520 after uint32 521 } 522 x.before = magic32 523 x.after = magic32 524 for delta := uint32(1); delta+delta > delta; delta += delta { 525 k := LoadUint32(&x.i) 526 if k != x.i { 527 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 528 } 529 x.i += delta 530 } 531 if x.before != magic32 || x.after != magic32 { 532 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 533 } 534 } 535 536 func TestLoadInt64(t *testing.T) { 537 if test64err != nil { 538 t.Skipf("Skipping 64-bit tests: %v", test64err) 539 } 540 var x struct { 541 before int64 542 i int64 543 after int64 544 } 545 x.before = magic64 546 x.after = magic64 547 for delta := int64(1); delta+delta > delta; delta += delta { 548 k := LoadInt64(&x.i) 549 if k != x.i { 550 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 551 } 552 x.i += delta 553 } 554 if x.before != magic64 || x.after != magic64 { 555 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 556 } 557 } 558 559 func TestLoadUint64(t *testing.T) { 560 if test64err != nil { 561 t.Skipf("Skipping 64-bit tests: %v", test64err) 562 } 563 var x struct { 564 before uint64 565 i uint64 566 after uint64 567 } 568 x.before = magic64 569 x.after = magic64 570 for delta := uint64(1); delta+delta > delta; delta += delta { 571 k := LoadUint64(&x.i) 572 if k != x.i { 573 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 574 } 575 x.i += delta 576 } 577 if x.before != magic64 || x.after != magic64 { 578 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 579 } 580 } 581 582 func TestLoadUintptr(t *testing.T) { 583 var x struct { 584 before uintptr 585 i uintptr 586 after uintptr 587 } 588 var m uint64 = magic64 589 magicptr := uintptr(m) 590 x.before = magicptr 591 x.after = magicptr 592 for delta := uintptr(1); delta+delta > delta; delta += delta { 593 k := LoadUintptr(&x.i) 594 if k != x.i { 595 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 596 } 597 x.i += delta 598 } 599 if x.before != magicptr || x.after != magicptr { 600 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 601 } 602 } 603 604 func TestLoadPointer(t *testing.T) { 605 var x struct { 606 before uintptr 607 i unsafe.Pointer 608 after uintptr 609 } 610 var m uint64 = magic64 611 magicptr := uintptr(m) 612 x.before = magicptr 613 x.after = magicptr 614 for _, p := range testPointers() { 615 x.i = p 616 k := LoadPointer(&x.i) 617 if k != p { 618 t.Fatalf("p=%x k=%x", p, k) 619 } 620 } 621 if x.before != magicptr || x.after != magicptr { 622 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 623 } 624 } 625 626 func TestStoreInt32(t *testing.T) { 627 var x struct { 628 before int32 629 i int32 630 after int32 631 } 632 x.before = magic32 633 x.after = magic32 634 v := int32(0) 635 for delta := int32(1); delta+delta > delta; delta += delta { 636 StoreInt32(&x.i, v) 637 if x.i != v { 638 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 639 } 640 v += delta 641 } 642 if x.before != magic32 || x.after != magic32 { 643 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 644 } 645 } 646 647 func TestStoreUint32(t *testing.T) { 648 var x struct { 649 before uint32 650 i uint32 651 after uint32 652 } 653 x.before = magic32 654 x.after = magic32 655 v := uint32(0) 656 for delta := uint32(1); delta+delta > delta; delta += delta { 657 StoreUint32(&x.i, v) 658 if x.i != v { 659 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 660 } 661 v += delta 662 } 663 if x.before != magic32 || x.after != magic32 { 664 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 665 } 666 } 667 668 func TestStoreInt64(t *testing.T) { 669 if test64err != nil { 670 t.Skipf("Skipping 64-bit tests: %v", test64err) 671 } 672 var x struct { 673 before int64 674 i int64 675 after int64 676 } 677 x.before = magic64 678 x.after = magic64 679 v := int64(0) 680 for delta := int64(1); delta+delta > delta; delta += delta { 681 StoreInt64(&x.i, v) 682 if x.i != v { 683 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 684 } 685 v += delta 686 } 687 if x.before != magic64 || x.after != magic64 { 688 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 689 } 690 } 691 692 func TestStoreUint64(t *testing.T) { 693 if test64err != nil { 694 t.Skipf("Skipping 64-bit tests: %v", test64err) 695 } 696 var x struct { 697 before uint64 698 i uint64 699 after uint64 700 } 701 x.before = magic64 702 x.after = magic64 703 v := uint64(0) 704 for delta := uint64(1); delta+delta > delta; delta += delta { 705 StoreUint64(&x.i, v) 706 if x.i != v { 707 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 708 } 709 v += delta 710 } 711 if x.before != magic64 || x.after != magic64 { 712 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 713 } 714 } 715 716 func TestStoreUintptr(t *testing.T) { 717 var x struct { 718 before uintptr 719 i uintptr 720 after uintptr 721 } 722 var m uint64 = magic64 723 magicptr := uintptr(m) 724 x.before = magicptr 725 x.after = magicptr 726 v := uintptr(0) 727 for delta := uintptr(1); delta+delta > delta; delta += delta { 728 StoreUintptr(&x.i, v) 729 if x.i != v { 730 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 731 } 732 v += delta 733 } 734 if x.before != magicptr || x.after != magicptr { 735 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 736 } 737 } 738 739 func TestStorePointer(t *testing.T) { 740 var x struct { 741 before uintptr 742 i unsafe.Pointer 743 after uintptr 744 } 745 var m uint64 = magic64 746 magicptr := uintptr(m) 747 x.before = magicptr 748 x.after = magicptr 749 for _, p := range testPointers() { 750 StorePointer(&x.i, p) 751 if x.i != p { 752 t.Fatalf("x.i=%p p=%p", x.i, p) 753 } 754 } 755 if x.before != magicptr || x.after != magicptr { 756 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 757 } 758 } 759 760 // Tests of correct behavior, with contention. 761 // (Is the function atomic?) 762 // 763 // For each function, we write a "hammer" function that repeatedly 764 // uses the atomic operation to add 1 to a value. After running 765 // multiple hammers in parallel, check that we end with the correct 766 // total. 767 // Swap can't add 1, so it uses a different scheme. 768 // The functions repeatedly generate a pseudo-random number such that 769 // low bits are equal to high bits, swap, check that the old value 770 // has low and high bits equal. 771 772 var hammer32 = map[string]func(*uint32, int){ 773 "SwapInt32": hammerSwapInt32, 774 "SwapUint32": hammerSwapUint32, 775 "SwapUintptr": hammerSwapUintptr32, 776 "AddInt32": hammerAddInt32, 777 "AddUint32": hammerAddUint32, 778 "AddUintptr": hammerAddUintptr32, 779 "CompareAndSwapInt32": hammerCompareAndSwapInt32, 780 "CompareAndSwapUint32": hammerCompareAndSwapUint32, 781 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr32, 782 } 783 784 func init() { 785 var v uint64 = 1 << 50 786 if uintptr(v) != 0 { 787 // 64-bit system; clear uintptr tests 788 delete(hammer32, "SwapUintptr") 789 delete(hammer32, "AddUintptr") 790 delete(hammer32, "CompareAndSwapUintptr") 791 } 792 } 793 794 func hammerSwapInt32(uaddr *uint32, count int) { 795 addr := (*int32)(unsafe.Pointer(uaddr)) 796 seed := int(uintptr(unsafe.Pointer(&count))) 797 for i := 0; i < count; i++ { 798 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 799 old := uint32(SwapInt32(addr, int32(new))) 800 if old>>16 != old<<16>>16 { 801 panic(fmt.Sprintf("SwapInt32 is not atomic: %v", old)) 802 } 803 } 804 } 805 806 func hammerSwapUint32(addr *uint32, count int) { 807 seed := int(uintptr(unsafe.Pointer(&count))) 808 for i := 0; i < count; i++ { 809 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 810 old := SwapUint32(addr, new) 811 if old>>16 != old<<16>>16 { 812 panic(fmt.Sprintf("SwapUint32 is not atomic: %v", old)) 813 } 814 } 815 } 816 817 func hammerSwapUintptr32(uaddr *uint32, count int) { 818 // only safe when uintptr is 32-bit. 819 // not called on 64-bit systems. 820 addr := (*uintptr)(unsafe.Pointer(uaddr)) 821 seed := int(uintptr(unsafe.Pointer(&count))) 822 for i := 0; i < count; i++ { 823 new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 824 old := SwapUintptr(addr, new) 825 if old>>16 != old<<16>>16 { 826 panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old)) 827 } 828 } 829 } 830 831 func hammerAddInt32(uaddr *uint32, count int) { 832 addr := (*int32)(unsafe.Pointer(uaddr)) 833 for i := 0; i < count; i++ { 834 AddInt32(addr, 1) 835 } 836 } 837 838 func hammerAddUint32(addr *uint32, count int) { 839 for i := 0; i < count; i++ { 840 AddUint32(addr, 1) 841 } 842 } 843 844 func hammerAddUintptr32(uaddr *uint32, count int) { 845 // only safe when uintptr is 32-bit. 846 // not called on 64-bit systems. 847 addr := (*uintptr)(unsafe.Pointer(uaddr)) 848 for i := 0; i < count; i++ { 849 AddUintptr(addr, 1) 850 } 851 } 852 853 func hammerCompareAndSwapInt32(uaddr *uint32, count int) { 854 addr := (*int32)(unsafe.Pointer(uaddr)) 855 for i := 0; i < count; i++ { 856 for { 857 v := LoadInt32(addr) 858 if CompareAndSwapInt32(addr, v, v+1) { 859 break 860 } 861 } 862 } 863 } 864 865 func hammerCompareAndSwapUint32(addr *uint32, count int) { 866 for i := 0; i < count; i++ { 867 for { 868 v := LoadUint32(addr) 869 if CompareAndSwapUint32(addr, v, v+1) { 870 break 871 } 872 } 873 } 874 } 875 876 func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) { 877 // only safe when uintptr is 32-bit. 878 // not called on 64-bit systems. 879 addr := (*uintptr)(unsafe.Pointer(uaddr)) 880 for i := 0; i < count; i++ { 881 for { 882 v := LoadUintptr(addr) 883 if CompareAndSwapUintptr(addr, v, v+1) { 884 break 885 } 886 } 887 } 888 } 889 890 func TestHammer32(t *testing.T) { 891 const p = 4 892 n := 100000 893 if testing.Short() { 894 n = 1000 895 } 896 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 897 898 for name, testf := range hammer32 { 899 c := make(chan int) 900 var val uint32 901 for i := 0; i < p; i++ { 902 go func() { 903 defer func() { 904 if err := recover(); err != nil { 905 t.Error(err.(string)) 906 } 907 c <- 1 908 }() 909 testf(&val, n) 910 }() 911 } 912 for i := 0; i < p; i++ { 913 <-c 914 } 915 if !strings.HasPrefix(name, "Swap") && val != uint32(n)*p { 916 t.Fatalf("%s: val=%d want %d", name, val, n*p) 917 } 918 } 919 } 920 921 var hammer64 = map[string]func(*uint64, int){ 922 "SwapInt64": hammerSwapInt64, 923 "SwapUint64": hammerSwapUint64, 924 "SwapUintptr": hammerSwapUintptr64, 925 "AddInt64": hammerAddInt64, 926 "AddUint64": hammerAddUint64, 927 "AddUintptr": hammerAddUintptr64, 928 "CompareAndSwapInt64": hammerCompareAndSwapInt64, 929 "CompareAndSwapUint64": hammerCompareAndSwapUint64, 930 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr64, 931 } 932 933 func init() { 934 var v uint64 = 1 << 50 935 if uintptr(v) == 0 { 936 // 32-bit system; clear uintptr tests 937 delete(hammer64, "SwapUintptr") 938 delete(hammer64, "AddUintptr") 939 delete(hammer64, "CompareAndSwapUintptr") 940 } 941 } 942 943 func hammerSwapInt64(uaddr *uint64, count int) { 944 addr := (*int64)(unsafe.Pointer(uaddr)) 945 seed := int(uintptr(unsafe.Pointer(&count))) 946 for i := 0; i < count; i++ { 947 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 948 old := uint64(SwapInt64(addr, int64(new))) 949 if old>>32 != old<<32>>32 { 950 panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) 951 } 952 } 953 } 954 955 func hammerSwapUint64(addr *uint64, count int) { 956 seed := int(uintptr(unsafe.Pointer(&count))) 957 for i := 0; i < count; i++ { 958 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 959 old := SwapUint64(addr, new) 960 if old>>32 != old<<32>>32 { 961 panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) 962 } 963 } 964 } 965 966 const arch32 = unsafe.Sizeof(uintptr(0)) == 4 967 968 func hammerSwapUintptr64(uaddr *uint64, count int) { 969 // only safe when uintptr is 64-bit. 970 // not called on 32-bit systems. 971 if !arch32 { 972 addr := (*uintptr)(unsafe.Pointer(uaddr)) 973 seed := int(uintptr(unsafe.Pointer(&count))) 974 for i := 0; i < count; i++ { 975 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 976 old := SwapUintptr(addr, new) 977 if old>>32 != old<<32>>32 { 978 panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) 979 } 980 } 981 } 982 } 983 984 func hammerAddInt64(uaddr *uint64, count int) { 985 addr := (*int64)(unsafe.Pointer(uaddr)) 986 for i := 0; i < count; i++ { 987 AddInt64(addr, 1) 988 } 989 } 990 991 func hammerAddUint64(addr *uint64, count int) { 992 for i := 0; i < count; i++ { 993 AddUint64(addr, 1) 994 } 995 } 996 997 func hammerAddUintptr64(uaddr *uint64, count int) { 998 // only safe when uintptr is 64-bit. 999 // not called on 32-bit systems. 1000 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1001 for i := 0; i < count; i++ { 1002 AddUintptr(addr, 1) 1003 } 1004 } 1005 1006 func hammerCompareAndSwapInt64(uaddr *uint64, count int) { 1007 addr := (*int64)(unsafe.Pointer(uaddr)) 1008 for i := 0; i < count; i++ { 1009 for { 1010 v := LoadInt64(addr) 1011 if CompareAndSwapInt64(addr, v, v+1) { 1012 break 1013 } 1014 } 1015 } 1016 } 1017 1018 func hammerCompareAndSwapUint64(addr *uint64, count int) { 1019 for i := 0; i < count; i++ { 1020 for { 1021 v := LoadUint64(addr) 1022 if CompareAndSwapUint64(addr, v, v+1) { 1023 break 1024 } 1025 } 1026 } 1027 } 1028 1029 func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) { 1030 // only safe when uintptr is 64-bit. 1031 // not called on 32-bit systems. 1032 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1033 for i := 0; i < count; i++ { 1034 for { 1035 v := LoadUintptr(addr) 1036 if CompareAndSwapUintptr(addr, v, v+1) { 1037 break 1038 } 1039 } 1040 } 1041 } 1042 1043 func TestHammer64(t *testing.T) { 1044 if test64err != nil { 1045 t.Skipf("Skipping 64-bit tests: %v", test64err) 1046 } 1047 const p = 4 1048 n := 100000 1049 if testing.Short() { 1050 n = 1000 1051 } 1052 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 1053 1054 for name, testf := range hammer64 { 1055 c := make(chan int) 1056 var val uint64 1057 for i := 0; i < p; i++ { 1058 go func() { 1059 defer func() { 1060 if err := recover(); err != nil { 1061 t.Error(err.(string)) 1062 } 1063 c <- 1 1064 }() 1065 testf(&val, n) 1066 }() 1067 } 1068 for i := 0; i < p; i++ { 1069 <-c 1070 } 1071 if !strings.HasPrefix(name, "Swap") && val != uint64(n)*p { 1072 t.Fatalf("%s: val=%d want %d", name, val, n*p) 1073 } 1074 } 1075 } 1076 1077 func hammerStoreLoadInt32(t *testing.T, paddr unsafe.Pointer) { 1078 addr := (*int32)(paddr) 1079 v := LoadInt32(addr) 1080 vlo := v & ((1 << 16) - 1) 1081 vhi := v >> 16 1082 if vlo != vhi { 1083 t.Fatalf("Int32: %#x != %#x", vlo, vhi) 1084 } 1085 new := v + 1 + 1<<16 1086 if vlo == 1e4 { 1087 new = 0 1088 } 1089 StoreInt32(addr, new) 1090 } 1091 1092 func hammerStoreLoadUint32(t *testing.T, paddr unsafe.Pointer) { 1093 addr := (*uint32)(paddr) 1094 v := LoadUint32(addr) 1095 vlo := v & ((1 << 16) - 1) 1096 vhi := v >> 16 1097 if vlo != vhi { 1098 t.Fatalf("Uint32: %#x != %#x", vlo, vhi) 1099 } 1100 new := v + 1 + 1<<16 1101 if vlo == 1e4 { 1102 new = 0 1103 } 1104 StoreUint32(addr, new) 1105 } 1106 1107 func hammerStoreLoadInt64(t *testing.T, paddr unsafe.Pointer) { 1108 addr := (*int64)(paddr) 1109 v := LoadInt64(addr) 1110 vlo := v & ((1 << 32) - 1) 1111 vhi := v >> 32 1112 if vlo != vhi { 1113 t.Fatalf("Int64: %#x != %#x", vlo, vhi) 1114 } 1115 new := v + 1 + 1<<32 1116 StoreInt64(addr, new) 1117 } 1118 1119 func hammerStoreLoadUint64(t *testing.T, paddr unsafe.Pointer) { 1120 addr := (*uint64)(paddr) 1121 v := LoadUint64(addr) 1122 vlo := v & ((1 << 32) - 1) 1123 vhi := v >> 32 1124 if vlo != vhi { 1125 t.Fatalf("Uint64: %#x != %#x", vlo, vhi) 1126 } 1127 new := v + 1 + 1<<32 1128 StoreUint64(addr, new) 1129 } 1130 1131 func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) { 1132 addr := (*uintptr)(paddr) 1133 v := LoadUintptr(addr) 1134 new := v 1135 if arch32 { 1136 vlo := v & ((1 << 16) - 1) 1137 vhi := v >> 16 1138 if vlo != vhi { 1139 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 1140 } 1141 new = v + 1 + 1<<16 1142 if vlo == 1e4 { 1143 new = 0 1144 } 1145 } else { 1146 vlo := v & ((1 << 32) - 1) 1147 vhi := v >> 32 1148 if vlo != vhi { 1149 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 1150 } 1151 inc := uint64(1 + 1<<32) 1152 new = v + uintptr(inc) 1153 } 1154 StoreUintptr(addr, new) 1155 } 1156 1157 //go:nocheckptr 1158 // This code is just testing that LoadPointer/StorePointer operate 1159 // atomically; it's not actually calculating pointers. 1160 func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) { 1161 addr := (*unsafe.Pointer)(paddr) 1162 v := uintptr(LoadPointer(addr)) 1163 new := v 1164 if arch32 { 1165 vlo := v & ((1 << 16) - 1) 1166 vhi := v >> 16 1167 if vlo != vhi { 1168 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 1169 } 1170 new = v + 1 + 1<<16 1171 if vlo == 1e4 { 1172 new = 0 1173 } 1174 } else { 1175 vlo := v & ((1 << 32) - 1) 1176 vhi := v >> 32 1177 if vlo != vhi { 1178 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 1179 } 1180 inc := uint64(1 + 1<<32) 1181 new = v + uintptr(inc) 1182 } 1183 StorePointer(addr, unsafe.Pointer(new)) 1184 } 1185 1186 func TestHammerStoreLoad(t *testing.T) { 1187 var tests []func(*testing.T, unsafe.Pointer) 1188 tests = append(tests, hammerStoreLoadInt32, hammerStoreLoadUint32, 1189 hammerStoreLoadUintptr, hammerStoreLoadPointer) 1190 if test64err == nil { 1191 tests = append(tests, hammerStoreLoadInt64, hammerStoreLoadUint64) 1192 } 1193 n := int(1e6) 1194 if testing.Short() { 1195 n = int(1e4) 1196 } 1197 const procs = 8 1198 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs)) 1199 for _, tt := range tests { 1200 c := make(chan int) 1201 var val uint64 1202 for p := 0; p < procs; p++ { 1203 go func() { 1204 for i := 0; i < n; i++ { 1205 tt(t, unsafe.Pointer(&val)) 1206 } 1207 c <- 1 1208 }() 1209 } 1210 for p := 0; p < procs; p++ { 1211 <-c 1212 } 1213 } 1214 } 1215 1216 func TestStoreLoadSeqCst32(t *testing.T) { 1217 if runtime.NumCPU() == 1 { 1218 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1219 } 1220 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1221 N := int32(1e3) 1222 if testing.Short() { 1223 N = int32(1e2) 1224 } 1225 c := make(chan bool, 2) 1226 X := [2]int32{} 1227 ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}} 1228 for p := 0; p < 2; p++ { 1229 go func(me int) { 1230 he := 1 - me 1231 for i := int32(1); i < N; i++ { 1232 StoreInt32(&X[me], i) 1233 my := LoadInt32(&X[he]) 1234 StoreInt32(&ack[me][i%3], my) 1235 for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ { 1236 if w%1000 == 0 { 1237 runtime.Gosched() 1238 } 1239 } 1240 his := LoadInt32(&ack[he][i%3]) 1241 if (my != i && my != i-1) || (his != i && his != i-1) { 1242 t.Errorf("invalid values: %d/%d (%d)", my, his, i) 1243 break 1244 } 1245 if my != i && his != i { 1246 t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 1247 break 1248 } 1249 StoreInt32(&ack[me][(i-1)%3], -1) 1250 } 1251 c <- true 1252 }(p) 1253 } 1254 <-c 1255 <-c 1256 } 1257 1258 func TestStoreLoadSeqCst64(t *testing.T) { 1259 if runtime.NumCPU() == 1 { 1260 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1261 } 1262 if test64err != nil { 1263 t.Skipf("Skipping 64-bit tests: %v", test64err) 1264 } 1265 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1266 N := int64(1e3) 1267 if testing.Short() { 1268 N = int64(1e2) 1269 } 1270 c := make(chan bool, 2) 1271 X := [2]int64{} 1272 ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}} 1273 for p := 0; p < 2; p++ { 1274 go func(me int) { 1275 he := 1 - me 1276 for i := int64(1); i < N; i++ { 1277 StoreInt64(&X[me], i) 1278 my := LoadInt64(&X[he]) 1279 StoreInt64(&ack[me][i%3], my) 1280 for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ { 1281 if w%1000 == 0 { 1282 runtime.Gosched() 1283 } 1284 } 1285 his := LoadInt64(&ack[he][i%3]) 1286 if (my != i && my != i-1) || (his != i && his != i-1) { 1287 t.Errorf("invalid values: %d/%d (%d)", my, his, i) 1288 break 1289 } 1290 if my != i && his != i { 1291 t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 1292 break 1293 } 1294 StoreInt64(&ack[me][(i-1)%3], -1) 1295 } 1296 c <- true 1297 }(p) 1298 } 1299 <-c 1300 <-c 1301 } 1302 1303 func TestStoreLoadRelAcq32(t *testing.T) { 1304 if runtime.NumCPU() == 1 { 1305 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1306 } 1307 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1308 N := int32(1e3) 1309 if testing.Short() { 1310 N = int32(1e2) 1311 } 1312 c := make(chan bool, 2) 1313 type Data struct { 1314 signal int32 1315 pad1 [128]int8 1316 data1 int32 1317 pad2 [128]int8 1318 data2 float32 1319 } 1320 var X Data 1321 for p := int32(0); p < 2; p++ { 1322 go func(p int32) { 1323 for i := int32(1); i < N; i++ { 1324 if (i+p)%2 == 0 { 1325 X.data1 = i 1326 X.data2 = float32(i) 1327 StoreInt32(&X.signal, i) 1328 } else { 1329 for w := 1; LoadInt32(&X.signal) != i; w++ { 1330 if w%1000 == 0 { 1331 runtime.Gosched() 1332 } 1333 } 1334 d1 := X.data1 1335 d2 := X.data2 1336 if d1 != i || d2 != float32(i) { 1337 t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i) 1338 break 1339 } 1340 } 1341 } 1342 c <- true 1343 }(p) 1344 } 1345 <-c 1346 <-c 1347 } 1348 1349 func TestStoreLoadRelAcq64(t *testing.T) { 1350 if runtime.NumCPU() == 1 { 1351 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1352 } 1353 if test64err != nil { 1354 t.Skipf("Skipping 64-bit tests: %v", test64err) 1355 } 1356 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1357 N := int64(1e3) 1358 if testing.Short() { 1359 N = int64(1e2) 1360 } 1361 c := make(chan bool, 2) 1362 type Data struct { 1363 signal int64 1364 pad1 [128]int8 1365 data1 int64 1366 pad2 [128]int8 1367 data2 float64 1368 } 1369 var X Data 1370 for p := int64(0); p < 2; p++ { 1371 go func(p int64) { 1372 for i := int64(1); i < N; i++ { 1373 if (i+p)%2 == 0 { 1374 X.data1 = i 1375 X.data2 = float64(i) 1376 StoreInt64(&X.signal, i) 1377 } else { 1378 for w := 1; LoadInt64(&X.signal) != i; w++ { 1379 if w%1000 == 0 { 1380 runtime.Gosched() 1381 } 1382 } 1383 d1 := X.data1 1384 d2 := X.data2 1385 if d1 != i || d2 != float64(i) { 1386 t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i) 1387 break 1388 } 1389 } 1390 } 1391 c <- true 1392 }(p) 1393 } 1394 <-c 1395 <-c 1396 } 1397 1398 func shouldPanic(t *testing.T, name string, f func()) { 1399 defer func() { 1400 // Check that all GC maps are sane. 1401 runtime.GC() 1402 1403 err := recover() 1404 want := "unaligned 64-bit atomic operation" 1405 if err == nil { 1406 t.Errorf("%s did not panic", name) 1407 } else if s, _ := err.(string); s != want { 1408 t.Errorf("%s: wanted panic %q, got %q", name, want, err) 1409 } 1410 }() 1411 f() 1412 } 1413 1414 func TestUnaligned64(t *testing.T) { 1415 // Unaligned 64-bit atomics on 32-bit systems are 1416 // a continual source of pain. Test that on 32-bit systems they crash 1417 // instead of failing silently. 1418 if !arch32 { 1419 t.Skip("test only runs on 32-bit systems") 1420 } 1421 1422 x := make([]uint32, 4) 1423 p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned 1424 1425 shouldPanic(t, "LoadUint64", func() { LoadUint64(p) }) 1426 shouldPanic(t, "StoreUint64", func() { StoreUint64(p, 1) }) 1427 shouldPanic(t, "CompareAndSwapUint64", func() { CompareAndSwapUint64(p, 1, 2) }) 1428 shouldPanic(t, "AddUint64", func() { AddUint64(p, 3) }) 1429 } 1430 1431 func TestNilDeref(t *testing.T) { 1432 funcs := [...]func(){ 1433 func() { CompareAndSwapInt32(nil, 0, 0) }, 1434 func() { CompareAndSwapInt64(nil, 0, 0) }, 1435 func() { CompareAndSwapUint32(nil, 0, 0) }, 1436 func() { CompareAndSwapUint64(nil, 0, 0) }, 1437 func() { CompareAndSwapUintptr(nil, 0, 0) }, 1438 func() { CompareAndSwapPointer(nil, nil, nil) }, 1439 func() { SwapInt32(nil, 0) }, 1440 func() { SwapUint32(nil, 0) }, 1441 func() { SwapInt64(nil, 0) }, 1442 func() { SwapUint64(nil, 0) }, 1443 func() { SwapUintptr(nil, 0) }, 1444 func() { SwapPointer(nil, nil) }, 1445 func() { AddInt32(nil, 0) }, 1446 func() { AddUint32(nil, 0) }, 1447 func() { AddInt64(nil, 0) }, 1448 func() { AddUint64(nil, 0) }, 1449 func() { AddUintptr(nil, 0) }, 1450 func() { LoadInt32(nil) }, 1451 func() { LoadInt64(nil) }, 1452 func() { LoadUint32(nil) }, 1453 func() { LoadUint64(nil) }, 1454 func() { LoadUintptr(nil) }, 1455 func() { LoadPointer(nil) }, 1456 func() { StoreInt32(nil, 0) }, 1457 func() { StoreInt64(nil, 0) }, 1458 func() { StoreUint32(nil, 0) }, 1459 func() { StoreUint64(nil, 0) }, 1460 func() { StoreUintptr(nil, 0) }, 1461 func() { StorePointer(nil, nil) }, 1462 } 1463 for _, f := range funcs { 1464 func() { 1465 defer func() { 1466 runtime.GC() 1467 recover() 1468 }() 1469 f() 1470 }() 1471 } 1472 }