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