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