github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/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 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); 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); 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); 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); 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 "SwapPointer": hammerSwapPointer32, 763 "AddInt32": hammerAddInt32, 764 "AddUint32": hammerAddUint32, 765 "AddUintptr": hammerAddUintptr32, 766 "CompareAndSwapInt32": hammerCompareAndSwapInt32, 767 "CompareAndSwapUint32": hammerCompareAndSwapUint32, 768 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr32, 769 "CompareAndSwapPointer": hammerCompareAndSwapPointer32, 770 } 771 772 func init() { 773 var v uint64 = 1 << 50 774 if uintptr(v) != 0 { 775 // 64-bit system; clear uintptr tests 776 delete(hammer32, "SwapUintptr") 777 delete(hammer32, "SwapPointer") 778 delete(hammer32, "AddUintptr") 779 delete(hammer32, "CompareAndSwapUintptr") 780 delete(hammer32, "CompareAndSwapPointer") 781 } 782 } 783 784 func hammerSwapInt32(uaddr *uint32, count int) { 785 addr := (*int32)(unsafe.Pointer(uaddr)) 786 seed := int(uintptr(unsafe.Pointer(&count))) 787 for i := 0; i < count; i++ { 788 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 789 old := uint32(SwapInt32(addr, int32(new))) 790 if old>>16 != old<<16>>16 { 791 panic(fmt.Sprintf("SwapInt32 is not atomic: %v", old)) 792 } 793 } 794 } 795 796 func hammerSwapUint32(addr *uint32, count int) { 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 := SwapUint32(addr, new) 801 if old>>16 != old<<16>>16 { 802 panic(fmt.Sprintf("SwapUint32 is not atomic: %v", old)) 803 } 804 } 805 } 806 807 func hammerSwapUintptr32(uaddr *uint32, count int) { 808 // only safe when uintptr is 32-bit. 809 // not called on 64-bit systems. 810 addr := (*uintptr)(unsafe.Pointer(uaddr)) 811 seed := int(uintptr(unsafe.Pointer(&count))) 812 for i := 0; i < count; i++ { 813 new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 814 old := SwapUintptr(addr, new) 815 if old>>16 != old<<16>>16 { 816 panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old)) 817 } 818 } 819 } 820 821 func hammerSwapPointer32(uaddr *uint32, count int) { 822 // only safe when uintptr is 32-bit. 823 // not called on 64-bit systems. 824 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 825 seed := int(uintptr(unsafe.Pointer(&count))) 826 for i := 0; i < count; i++ { 827 new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 828 old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) 829 if old>>16 != old<<16>>16 { 830 panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old)) 831 } 832 } 833 } 834 835 func hammerAddInt32(uaddr *uint32, count int) { 836 addr := (*int32)(unsafe.Pointer(uaddr)) 837 for i := 0; i < count; i++ { 838 AddInt32(addr, 1) 839 } 840 } 841 842 func hammerAddUint32(addr *uint32, count int) { 843 for i := 0; i < count; i++ { 844 AddUint32(addr, 1) 845 } 846 } 847 848 func hammerAddUintptr32(uaddr *uint32, count int) { 849 // only safe when uintptr is 32-bit. 850 // not called on 64-bit systems. 851 addr := (*uintptr)(unsafe.Pointer(uaddr)) 852 for i := 0; i < count; i++ { 853 AddUintptr(addr, 1) 854 } 855 } 856 857 func hammerCompareAndSwapInt32(uaddr *uint32, count int) { 858 addr := (*int32)(unsafe.Pointer(uaddr)) 859 for i := 0; i < count; i++ { 860 for { 861 v := LoadInt32(addr) 862 if CompareAndSwapInt32(addr, v, v+1) { 863 break 864 } 865 } 866 } 867 } 868 869 func hammerCompareAndSwapUint32(addr *uint32, count int) { 870 for i := 0; i < count; i++ { 871 for { 872 v := LoadUint32(addr) 873 if CompareAndSwapUint32(addr, v, v+1) { 874 break 875 } 876 } 877 } 878 } 879 880 func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) { 881 // only safe when uintptr is 32-bit. 882 // not called on 64-bit systems. 883 addr := (*uintptr)(unsafe.Pointer(uaddr)) 884 for i := 0; i < count; i++ { 885 for { 886 v := LoadUintptr(addr) 887 if CompareAndSwapUintptr(addr, v, v+1) { 888 break 889 } 890 } 891 } 892 } 893 894 func hammerCompareAndSwapPointer32(uaddr *uint32, count int) { 895 // only safe when uintptr is 32-bit. 896 // not called on 64-bit systems. 897 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 898 for i := 0; i < count; i++ { 899 for { 900 v := LoadPointer(addr) 901 if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) { 902 break 903 } 904 } 905 } 906 } 907 908 func TestHammer32(t *testing.T) { 909 const p = 4 910 n := 100000 911 if testing.Short() { 912 n = 1000 913 } 914 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 915 916 for name, testf := range hammer32 { 917 c := make(chan int) 918 var val uint32 919 for i := 0; i < p; i++ { 920 go func() { 921 defer func() { 922 if err := recover(); err != nil { 923 t.Error(err.(string)) 924 } 925 c <- 1 926 }() 927 testf(&val, n) 928 }() 929 } 930 for i := 0; i < p; i++ { 931 <-c 932 } 933 if !strings.HasPrefix(name, "Swap") && val != uint32(n)*p { 934 t.Fatalf("%s: val=%d want %d", name, val, n*p) 935 } 936 } 937 } 938 939 var hammer64 = map[string]func(*uint64, int){ 940 "SwapInt64": hammerSwapInt64, 941 "SwapUint64": hammerSwapUint64, 942 "SwapUintptr": hammerSwapUintptr64, 943 "SwapPointer": hammerSwapPointer64, 944 "AddInt64": hammerAddInt64, 945 "AddUint64": hammerAddUint64, 946 "AddUintptr": hammerAddUintptr64, 947 "CompareAndSwapInt64": hammerCompareAndSwapInt64, 948 "CompareAndSwapUint64": hammerCompareAndSwapUint64, 949 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr64, 950 "CompareAndSwapPointer": hammerCompareAndSwapPointer64, 951 } 952 953 func init() { 954 var v uint64 = 1 << 50 955 if uintptr(v) == 0 { 956 // 32-bit system; clear uintptr tests 957 delete(hammer64, "SwapUintptr") 958 delete(hammer64, "SwapPointer") 959 delete(hammer64, "AddUintptr") 960 delete(hammer64, "CompareAndSwapUintptr") 961 delete(hammer64, "CompareAndSwapPointer") 962 } 963 } 964 965 func hammerSwapInt64(uaddr *uint64, count int) { 966 addr := (*int64)(unsafe.Pointer(uaddr)) 967 seed := int(uintptr(unsafe.Pointer(&count))) 968 for i := 0; i < count; i++ { 969 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 970 old := uint64(SwapInt64(addr, int64(new))) 971 if old>>32 != old<<32>>32 { 972 panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) 973 } 974 } 975 } 976 977 func hammerSwapUint64(addr *uint64, count int) { 978 seed := int(uintptr(unsafe.Pointer(&count))) 979 for i := 0; i < count; i++ { 980 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 981 old := SwapUint64(addr, new) 982 if old>>32 != old<<32>>32 { 983 panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) 984 } 985 } 986 } 987 988 func hammerSwapUintptr64(uaddr *uint64, count int) { 989 // only safe when uintptr is 64-bit. 990 // not called on 32-bit systems. 991 addr := (*uintptr)(unsafe.Pointer(uaddr)) 992 seed := int(uintptr(unsafe.Pointer(&count))) 993 for i := 0; i < count; i++ { 994 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 995 old := SwapUintptr(addr, new) 996 if old>>32 != old<<32>>32 { 997 panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) 998 } 999 } 1000 } 1001 1002 func hammerSwapPointer64(uaddr *uint64, count int) { 1003 // only safe when uintptr is 64-bit. 1004 // not called on 32-bit systems. 1005 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 1006 seed := int(uintptr(unsafe.Pointer(&count))) 1007 for i := 0; i < count; i++ { 1008 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 1009 old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) 1010 if old>>32 != old<<32>>32 { 1011 panic(fmt.Sprintf("SwapPointer is not atomic: %v", old)) 1012 } 1013 } 1014 } 1015 1016 func hammerAddInt64(uaddr *uint64, count int) { 1017 addr := (*int64)(unsafe.Pointer(uaddr)) 1018 for i := 0; i < count; i++ { 1019 AddInt64(addr, 1) 1020 } 1021 } 1022 1023 func hammerAddUint64(addr *uint64, count int) { 1024 for i := 0; i < count; i++ { 1025 AddUint64(addr, 1) 1026 } 1027 } 1028 1029 func hammerAddUintptr64(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 AddUintptr(addr, 1) 1035 } 1036 } 1037 1038 func hammerCompareAndSwapInt64(uaddr *uint64, count int) { 1039 addr := (*int64)(unsafe.Pointer(uaddr)) 1040 for i := 0; i < count; i++ { 1041 for { 1042 v := LoadInt64(addr) 1043 if CompareAndSwapInt64(addr, v, v+1) { 1044 break 1045 } 1046 } 1047 } 1048 } 1049 1050 func hammerCompareAndSwapUint64(addr *uint64, count int) { 1051 for i := 0; i < count; i++ { 1052 for { 1053 v := LoadUint64(addr) 1054 if CompareAndSwapUint64(addr, v, v+1) { 1055 break 1056 } 1057 } 1058 } 1059 } 1060 1061 func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) { 1062 // only safe when uintptr is 64-bit. 1063 // not called on 32-bit systems. 1064 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1065 for i := 0; i < count; i++ { 1066 for { 1067 v := LoadUintptr(addr) 1068 if CompareAndSwapUintptr(addr, v, v+1) { 1069 break 1070 } 1071 } 1072 } 1073 } 1074 1075 func hammerCompareAndSwapPointer64(uaddr *uint64, count int) { 1076 // only safe when uintptr is 64-bit. 1077 // not called on 32-bit systems. 1078 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 1079 for i := 0; i < count; i++ { 1080 for { 1081 v := LoadPointer(addr) 1082 if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) { 1083 break 1084 } 1085 } 1086 } 1087 } 1088 1089 func TestHammer64(t *testing.T) { 1090 if test64err != nil { 1091 t.Skipf("Skipping 64-bit tests: %v", test64err) 1092 } 1093 const p = 4 1094 n := 100000 1095 if testing.Short() { 1096 n = 1000 1097 } 1098 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 1099 1100 for name, testf := range hammer64 { 1101 c := make(chan int) 1102 var val uint64 1103 for i := 0; i < p; i++ { 1104 go func() { 1105 defer func() { 1106 if err := recover(); err != nil { 1107 t.Error(err.(string)) 1108 } 1109 c <- 1 1110 }() 1111 testf(&val, n) 1112 }() 1113 } 1114 for i := 0; i < p; i++ { 1115 <-c 1116 } 1117 if !strings.HasPrefix(name, "Swap") && val != uint64(n)*p { 1118 t.Fatalf("%s: val=%d want %d", name, val, n*p) 1119 } 1120 } 1121 } 1122 1123 func hammerStoreLoadInt32(t *testing.T, paddr unsafe.Pointer) { 1124 addr := (*int32)(paddr) 1125 v := LoadInt32(addr) 1126 vlo := v & ((1 << 16) - 1) 1127 vhi := v >> 16 1128 if vlo != vhi { 1129 t.Fatalf("Int32: %#x != %#x", vlo, vhi) 1130 } 1131 new := v + 1 + 1<<16 1132 if vlo == 1e4 { 1133 new = 0 1134 } 1135 StoreInt32(addr, new) 1136 } 1137 1138 func hammerStoreLoadUint32(t *testing.T, paddr unsafe.Pointer) { 1139 addr := (*uint32)(paddr) 1140 v := LoadUint32(addr) 1141 vlo := v & ((1 << 16) - 1) 1142 vhi := v >> 16 1143 if vlo != vhi { 1144 t.Fatalf("Uint32: %#x != %#x", vlo, vhi) 1145 } 1146 new := v + 1 + 1<<16 1147 if vlo == 1e4 { 1148 new = 0 1149 } 1150 StoreUint32(addr, new) 1151 } 1152 1153 func hammerStoreLoadInt64(t *testing.T, paddr unsafe.Pointer) { 1154 addr := (*int64)(paddr) 1155 v := LoadInt64(addr) 1156 vlo := v & ((1 << 32) - 1) 1157 vhi := v >> 32 1158 if vlo != vhi { 1159 t.Fatalf("Int64: %#x != %#x", vlo, vhi) 1160 } 1161 new := v + 1 + 1<<32 1162 StoreInt64(addr, new) 1163 } 1164 1165 func hammerStoreLoadUint64(t *testing.T, paddr unsafe.Pointer) { 1166 addr := (*uint64)(paddr) 1167 v := LoadUint64(addr) 1168 vlo := v & ((1 << 32) - 1) 1169 vhi := v >> 32 1170 if vlo != vhi { 1171 t.Fatalf("Uint64: %#x != %#x", vlo, vhi) 1172 } 1173 new := v + 1 + 1<<32 1174 StoreUint64(addr, new) 1175 } 1176 1177 func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) { 1178 addr := (*uintptr)(paddr) 1179 var test64 uint64 = 1 << 50 1180 arch32 := uintptr(test64) == 0 1181 v := LoadUintptr(addr) 1182 new := v 1183 if arch32 { 1184 vlo := v & ((1 << 16) - 1) 1185 vhi := v >> 16 1186 if vlo != vhi { 1187 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 1188 } 1189 new = v + 1 + 1<<16 1190 if vlo == 1e4 { 1191 new = 0 1192 } 1193 } else { 1194 vlo := v & ((1 << 32) - 1) 1195 vhi := v >> 32 1196 if vlo != vhi { 1197 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 1198 } 1199 inc := uint64(1 + 1<<32) 1200 new = v + uintptr(inc) 1201 } 1202 StoreUintptr(addr, new) 1203 } 1204 1205 func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) { 1206 addr := (*unsafe.Pointer)(paddr) 1207 var test64 uint64 = 1 << 50 1208 arch32 := uintptr(test64) == 0 1209 v := uintptr(LoadPointer(addr)) 1210 new := v 1211 if arch32 { 1212 vlo := v & ((1 << 16) - 1) 1213 vhi := v >> 16 1214 if vlo != vhi { 1215 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 1216 } 1217 new = v + 1 + 1<<16 1218 if vlo == 1e4 { 1219 new = 0 1220 } 1221 } else { 1222 vlo := v & ((1 << 32) - 1) 1223 vhi := v >> 32 1224 if vlo != vhi { 1225 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 1226 } 1227 inc := uint64(1 + 1<<32) 1228 new = v + uintptr(inc) 1229 } 1230 StorePointer(addr, unsafe.Pointer(new)) 1231 } 1232 1233 func TestHammerStoreLoad(t *testing.T) { 1234 var tests []func(*testing.T, unsafe.Pointer) 1235 tests = append(tests, hammerStoreLoadInt32, hammerStoreLoadUint32, 1236 hammerStoreLoadUintptr, hammerStoreLoadPointer) 1237 if test64err == nil { 1238 tests = append(tests, hammerStoreLoadInt64, hammerStoreLoadUint64) 1239 } 1240 n := int(1e6) 1241 if testing.Short() { 1242 n = int(1e4) 1243 } 1244 const procs = 8 1245 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs)) 1246 for _, tt := range tests { 1247 c := make(chan int) 1248 var val uint64 1249 for p := 0; p < procs; p++ { 1250 go func() { 1251 for i := 0; i < n; i++ { 1252 tt(t, unsafe.Pointer(&val)) 1253 } 1254 c <- 1 1255 }() 1256 } 1257 for p := 0; p < procs; p++ { 1258 <-c 1259 } 1260 } 1261 } 1262 1263 func TestStoreLoadSeqCst32(t *testing.T) { 1264 if runtime.NumCPU() == 1 { 1265 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1266 } 1267 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1268 N := int32(1e3) 1269 if testing.Short() { 1270 N = int32(1e2) 1271 } 1272 c := make(chan bool, 2) 1273 X := [2]int32{} 1274 ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}} 1275 for p := 0; p < 2; p++ { 1276 go func(me int) { 1277 he := 1 - me 1278 for i := int32(1); i < N; i++ { 1279 StoreInt32(&X[me], i) 1280 my := LoadInt32(&X[he]) 1281 StoreInt32(&ack[me][i%3], my) 1282 for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ { 1283 if w%1000 == 0 { 1284 runtime.Gosched() 1285 } 1286 } 1287 his := LoadInt32(&ack[he][i%3]) 1288 if (my != i && my != i-1) || (his != i && his != i-1) { 1289 t.Fatalf("invalid values: %d/%d (%d)", my, his, i) 1290 } 1291 if my != i && his != i { 1292 t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 1293 } 1294 StoreInt32(&ack[me][(i-1)%3], -1) 1295 } 1296 c <- true 1297 }(p) 1298 } 1299 <-c 1300 <-c 1301 } 1302 1303 func TestStoreLoadSeqCst64(t *testing.T) { 1304 if runtime.NumCPU() == 1 { 1305 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1306 } 1307 if test64err != nil { 1308 t.Skipf("Skipping 64-bit tests: %v", test64err) 1309 } 1310 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1311 N := int64(1e3) 1312 if testing.Short() { 1313 N = int64(1e2) 1314 } 1315 c := make(chan bool, 2) 1316 X := [2]int64{} 1317 ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}} 1318 for p := 0; p < 2; p++ { 1319 go func(me int) { 1320 he := 1 - me 1321 for i := int64(1); i < N; i++ { 1322 StoreInt64(&X[me], i) 1323 my := LoadInt64(&X[he]) 1324 StoreInt64(&ack[me][i%3], my) 1325 for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ { 1326 if w%1000 == 0 { 1327 runtime.Gosched() 1328 } 1329 } 1330 his := LoadInt64(&ack[he][i%3]) 1331 if (my != i && my != i-1) || (his != i && his != i-1) { 1332 t.Fatalf("invalid values: %d/%d (%d)", my, his, i) 1333 } 1334 if my != i && his != i { 1335 t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 1336 } 1337 StoreInt64(&ack[me][(i-1)%3], -1) 1338 } 1339 c <- true 1340 }(p) 1341 } 1342 <-c 1343 <-c 1344 } 1345 1346 func TestStoreLoadRelAcq32(t *testing.T) { 1347 if runtime.NumCPU() == 1 { 1348 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1349 } 1350 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1351 N := int32(1e3) 1352 if testing.Short() { 1353 N = int32(1e2) 1354 } 1355 c := make(chan bool, 2) 1356 type Data struct { 1357 signal int32 1358 pad1 [128]int8 1359 data1 int32 1360 pad2 [128]int8 1361 data2 float32 1362 } 1363 var X Data 1364 for p := int32(0); p < 2; p++ { 1365 go func(p int32) { 1366 for i := int32(1); i < N; i++ { 1367 if (i+p)%2 == 0 { 1368 X.data1 = i 1369 X.data2 = float32(i) 1370 StoreInt32(&X.signal, i) 1371 } else { 1372 for w := 1; LoadInt32(&X.signal) != i; w++ { 1373 if w%1000 == 0 { 1374 runtime.Gosched() 1375 } 1376 } 1377 d1 := X.data1 1378 d2 := X.data2 1379 if d1 != i || d2 != float32(i) { 1380 t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i) 1381 } 1382 } 1383 } 1384 c <- true 1385 }(p) 1386 } 1387 <-c 1388 <-c 1389 } 1390 1391 func TestStoreLoadRelAcq64(t *testing.T) { 1392 if runtime.NumCPU() == 1 { 1393 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1394 } 1395 if test64err != nil { 1396 t.Skipf("Skipping 64-bit tests: %v", test64err) 1397 } 1398 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1399 N := int64(1e3) 1400 if testing.Short() { 1401 N = int64(1e2) 1402 } 1403 c := make(chan bool, 2) 1404 type Data struct { 1405 signal int64 1406 pad1 [128]int8 1407 data1 int64 1408 pad2 [128]int8 1409 data2 float64 1410 } 1411 var X Data 1412 for p := int64(0); p < 2; p++ { 1413 go func(p int64) { 1414 for i := int64(1); i < N; i++ { 1415 if (i+p)%2 == 0 { 1416 X.data1 = i 1417 X.data2 = float64(i) 1418 StoreInt64(&X.signal, i) 1419 } else { 1420 for w := 1; LoadInt64(&X.signal) != i; w++ { 1421 if w%1000 == 0 { 1422 runtime.Gosched() 1423 } 1424 } 1425 d1 := X.data1 1426 d2 := X.data2 1427 if d1 != i || d2 != float64(i) { 1428 t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i) 1429 } 1430 } 1431 } 1432 c <- true 1433 }(p) 1434 } 1435 <-c 1436 <-c 1437 } 1438 1439 func shouldPanic(t *testing.T, name string, f func()) { 1440 defer func() { 1441 if recover() == nil { 1442 t.Errorf("%s did not panic", name) 1443 } 1444 }() 1445 f() 1446 } 1447 1448 func TestUnaligned64(t *testing.T) { 1449 // Unaligned 64-bit atomics on 32-bit systems are 1450 // a continual source of pain. Test that on 32-bit systems they crash 1451 // instead of failing silently. 1452 if unsafe.Sizeof(int(0)) != 4 { 1453 t.Skip("test only runs on 32-bit systems") 1454 } 1455 1456 x := make([]uint32, 4) 1457 p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned 1458 1459 shouldPanic(t, "LoadUint64", func() { LoadUint64(p) }) 1460 shouldPanic(t, "StoreUint64", func() { StoreUint64(p, 1) }) 1461 shouldPanic(t, "CompareAndSwapUint64", func() { CompareAndSwapUint64(p, 1, 2) }) 1462 shouldPanic(t, "AddUint64", func() { AddUint64(p, 3) }) 1463 } 1464 1465 func TestNilDeref(t *testing.T) { 1466 if p := runtime.GOOS + "/" + runtime.GOARCH; p == "freebsd/arm" || p == "netbsd/arm" { 1467 t.Skipf("issue 7338: skipping test on %q", p) 1468 } 1469 funcs := [...]func(){ 1470 func() { CompareAndSwapInt32(nil, 0, 0) }, 1471 func() { CompareAndSwapInt64(nil, 0, 0) }, 1472 func() { CompareAndSwapUint32(nil, 0, 0) }, 1473 func() { CompareAndSwapUint64(nil, 0, 0) }, 1474 func() { CompareAndSwapUintptr(nil, 0, 0) }, 1475 func() { CompareAndSwapPointer(nil, nil, nil) }, 1476 func() { SwapInt32(nil, 0) }, 1477 func() { SwapUint32(nil, 0) }, 1478 func() { SwapInt64(nil, 0) }, 1479 func() { SwapUint64(nil, 0) }, 1480 func() { SwapUintptr(nil, 0) }, 1481 func() { SwapPointer(nil, nil) }, 1482 func() { AddInt32(nil, 0) }, 1483 func() { AddUint32(nil, 0) }, 1484 func() { AddInt64(nil, 0) }, 1485 func() { AddUint64(nil, 0) }, 1486 func() { AddUintptr(nil, 0) }, 1487 func() { LoadInt32(nil) }, 1488 func() { LoadInt64(nil) }, 1489 func() { LoadUint32(nil) }, 1490 func() { LoadUint64(nil) }, 1491 func() { LoadUintptr(nil) }, 1492 func() { LoadPointer(nil) }, 1493 func() { StoreInt32(nil, 0) }, 1494 func() { StoreInt64(nil, 0) }, 1495 func() { StoreUint32(nil, 0) }, 1496 func() { StoreUint64(nil, 0) }, 1497 func() { StoreUintptr(nil, 0) }, 1498 func() { StorePointer(nil, nil) }, 1499 } 1500 for _, f := range funcs { 1501 func() { 1502 defer func() { 1503 runtime.GC() 1504 recover() 1505 }() 1506 f() 1507 }() 1508 } 1509 }