github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/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) { 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 !CompareAndSwapUint64(&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 CompareAndSwapUint64(&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 TestCompareAndSwapUintptr(t *testing.T) { 415 var x struct { 416 before uintptr 417 i uintptr 418 after uintptr 419 } 420 var m uint64 = magic64 421 magicptr := uintptr(m) 422 x.before = magicptr 423 x.after = magicptr 424 for val := uintptr(1); val+val > val; val += val { 425 x.i = val 426 if !CompareAndSwapUintptr(&x.i, val, val+1) { 427 t.Fatalf("should have swapped %#x %#x", val, val+1) 428 } 429 if x.i != val+1 { 430 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 431 } 432 x.i = val + 1 433 if CompareAndSwapUintptr(&x.i, val, val+2) { 434 t.Fatalf("should not have swapped %#x %#x", val, val+2) 435 } 436 if x.i != val+1 { 437 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 438 } 439 } 440 if x.before != magicptr || x.after != magicptr { 441 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 442 } 443 } 444 445 func TestCompareAndSwapPointer(t *testing.T) { 446 var x struct { 447 before uintptr 448 i unsafe.Pointer 449 after uintptr 450 } 451 var m uint64 = magic64 452 magicptr := uintptr(m) 453 x.before = magicptr 454 x.after = magicptr 455 for val := uintptr(1); val+val > val; val += val { 456 x.i = unsafe.Pointer(val) 457 if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) { 458 t.Fatalf("should have swapped %#x %#x", val, val+1) 459 } 460 if x.i != unsafe.Pointer(val+1) { 461 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 462 } 463 x.i = unsafe.Pointer(val + 1) 464 if CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+2)) { 465 t.Fatalf("should not have swapped %#x %#x", val, val+2) 466 } 467 if x.i != unsafe.Pointer(val+1) { 468 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 469 } 470 } 471 if x.before != magicptr || x.after != magicptr { 472 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 473 } 474 } 475 476 func TestLoadInt32(t *testing.T) { 477 var x struct { 478 before int32 479 i int32 480 after int32 481 } 482 x.before = magic32 483 x.after = magic32 484 for delta := int32(1); delta+delta > delta; delta += delta { 485 k := LoadInt32(&x.i) 486 if k != x.i { 487 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 488 } 489 x.i += delta 490 } 491 if x.before != magic32 || x.after != magic32 { 492 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 493 } 494 } 495 496 func TestLoadUint32(t *testing.T) { 497 var x struct { 498 before uint32 499 i uint32 500 after uint32 501 } 502 x.before = magic32 503 x.after = magic32 504 for delta := uint32(1); delta+delta > delta; delta += delta { 505 k := LoadUint32(&x.i) 506 if k != x.i { 507 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 508 } 509 x.i += delta 510 } 511 if x.before != magic32 || x.after != magic32 { 512 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 513 } 514 } 515 516 func TestLoadInt64(t *testing.T) { 517 if test64err != nil { 518 t.Skipf("Skipping 64-bit tests: %v", test64err) 519 } 520 var x struct { 521 before int64 522 i int64 523 after int64 524 } 525 x.before = magic64 526 x.after = magic64 527 for delta := int64(1); delta+delta > delta; delta += delta { 528 k := LoadInt64(&x.i) 529 if k != x.i { 530 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 531 } 532 x.i += delta 533 } 534 if x.before != magic64 || x.after != magic64 { 535 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 536 } 537 } 538 539 func TestLoadUint64(t *testing.T) { 540 if test64err != nil { 541 t.Skipf("Skipping 64-bit tests: %v", test64err) 542 } 543 var x struct { 544 before uint64 545 i uint64 546 after uint64 547 } 548 x.before = magic64 549 x.after = magic64 550 for delta := uint64(1); delta+delta > delta; delta += delta { 551 k := LoadUint64(&x.i) 552 if k != x.i { 553 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 554 } 555 x.i += delta 556 } 557 if x.before != magic64 || x.after != magic64 { 558 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 559 } 560 } 561 562 func TestLoadUintptr(t *testing.T) { 563 var x struct { 564 before uintptr 565 i uintptr 566 after uintptr 567 } 568 var m uint64 = magic64 569 magicptr := uintptr(m) 570 x.before = magicptr 571 x.after = magicptr 572 for delta := uintptr(1); delta+delta > delta; delta += delta { 573 k := LoadUintptr(&x.i) 574 if k != x.i { 575 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 576 } 577 x.i += delta 578 } 579 if x.before != magicptr || x.after != magicptr { 580 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 581 } 582 } 583 584 func TestLoadPointer(t *testing.T) { 585 var x struct { 586 before uintptr 587 i unsafe.Pointer 588 after uintptr 589 } 590 var m uint64 = magic64 591 magicptr := uintptr(m) 592 x.before = magicptr 593 x.after = magicptr 594 for delta := uintptr(1); delta+delta > delta; delta += delta { 595 k := LoadPointer(&x.i) 596 if k != x.i { 597 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 598 } 599 x.i = unsafe.Pointer(uintptr(x.i) + delta) 600 } 601 if x.before != magicptr || x.after != magicptr { 602 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 603 } 604 } 605 606 func TestStoreInt32(t *testing.T) { 607 var x struct { 608 before int32 609 i int32 610 after int32 611 } 612 x.before = magic32 613 x.after = magic32 614 v := int32(0) 615 for delta := int32(1); delta+delta > delta; delta += delta { 616 StoreInt32(&x.i, v) 617 if x.i != v { 618 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 619 } 620 v += delta 621 } 622 if x.before != magic32 || x.after != magic32 { 623 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 624 } 625 } 626 627 func TestStoreUint32(t *testing.T) { 628 var x struct { 629 before uint32 630 i uint32 631 after uint32 632 } 633 x.before = magic32 634 x.after = magic32 635 v := uint32(0) 636 for delta := uint32(1); delta+delta > delta; delta += delta { 637 StoreUint32(&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 TestStoreInt64(t *testing.T) { 649 if test64err != nil { 650 t.Skipf("Skipping 64-bit tests: %v", test64err) 651 } 652 var x struct { 653 before int64 654 i int64 655 after int64 656 } 657 x.before = magic64 658 x.after = magic64 659 v := int64(0) 660 for delta := int64(1); delta+delta > delta; delta += delta { 661 StoreInt64(&x.i, v) 662 if x.i != v { 663 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 664 } 665 v += delta 666 } 667 if x.before != magic64 || x.after != magic64 { 668 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 669 } 670 } 671 672 func TestStoreUint64(t *testing.T) { 673 if test64err != nil { 674 t.Skipf("Skipping 64-bit tests: %v", test64err) 675 } 676 var x struct { 677 before uint64 678 i uint64 679 after uint64 680 } 681 x.before = magic64 682 x.after = magic64 683 v := uint64(0) 684 for delta := uint64(1); delta+delta > delta; delta += delta { 685 StoreUint64(&x.i, v) 686 if x.i != v { 687 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 688 } 689 v += delta 690 } 691 if x.before != magic64 || x.after != magic64 { 692 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64)) 693 } 694 } 695 696 func TestStoreUintptr(t *testing.T) { 697 var x struct { 698 before uintptr 699 i uintptr 700 after uintptr 701 } 702 var m uint64 = magic64 703 magicptr := uintptr(m) 704 x.before = magicptr 705 x.after = magicptr 706 v := uintptr(0) 707 for delta := uintptr(1); delta+delta > delta; delta += delta { 708 StoreUintptr(&x.i, v) 709 if x.i != v { 710 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 711 } 712 v += delta 713 } 714 if x.before != magicptr || x.after != magicptr { 715 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 716 } 717 } 718 719 func TestStorePointer(t *testing.T) { 720 var x struct { 721 before uintptr 722 i unsafe.Pointer 723 after uintptr 724 } 725 var m uint64 = magic64 726 magicptr := uintptr(m) 727 x.before = magicptr 728 x.after = magicptr 729 v := unsafe.Pointer(uintptr(0)) 730 for delta := uintptr(1); delta+delta > delta; delta += delta { 731 StorePointer(&x.i, unsafe.Pointer(v)) 732 if x.i != v { 733 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 734 } 735 v = unsafe.Pointer(uintptr(v) + delta) 736 } 737 if x.before != magicptr || x.after != magicptr { 738 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 739 } 740 } 741 742 // Tests of correct behavior, with contention. 743 // (Is the function atomic?) 744 // 745 // For each function, we write a "hammer" function that repeatedly 746 // uses the atomic operation to add 1 to a value. After running 747 // multiple hammers in parallel, check that we end with the correct 748 // total. 749 // Swap can't add 1, so it uses a different scheme. 750 // The functions repeatedly generate a pseudo-random number such that 751 // low bits are equal to high bits, swap, check that the old value 752 // has low and high bits equal. 753 754 var hammer32 = map[string]func(*uint32, int){ 755 "SwapInt32": hammerSwapInt32, 756 "SwapUint32": hammerSwapUint32, 757 "SwapUintptr": hammerSwapUintptr32, 758 "SwapPointer": hammerSwapPointer32, 759 "AddInt32": hammerAddInt32, 760 "AddUint32": hammerAddUint32, 761 "AddUintptr": hammerAddUintptr32, 762 "CompareAndSwapInt32": hammerCompareAndSwapInt32, 763 "CompareAndSwapUint32": hammerCompareAndSwapUint32, 764 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr32, 765 "CompareAndSwapPointer": hammerCompareAndSwapPointer32, 766 } 767 768 func init() { 769 var v uint64 = 1 << 50 770 if uintptr(v) != 0 { 771 // 64-bit system; clear uintptr tests 772 delete(hammer32, "SwapUintptr") 773 delete(hammer32, "SwapPointer") 774 delete(hammer32, "AddUintptr") 775 delete(hammer32, "CompareAndSwapUintptr") 776 delete(hammer32, "CompareAndSwapPointer") 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: %v", old)) 813 } 814 } 815 } 816 817 func hammerSwapPointer32(uaddr *uint32, count int) { 818 // only safe when uintptr is 32-bit. 819 // not called on 64-bit systems. 820 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 821 seed := int(uintptr(unsafe.Pointer(&count))) 822 for i := 0; i < count; i++ { 823 new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 824 old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) 825 if old>>16 != old<<16>>16 { 826 panic(fmt.Sprintf("SwapPointer is not atomic: %v", old)) 827 } 828 } 829 } 830 831 func hammerAddInt32(uaddr *uint32, count int) { 832 addr := (*int32)(unsafe.Pointer(uaddr)) 833 for i := 0; i < count; i++ { 834 AddInt32(addr, 1) 835 } 836 } 837 838 func hammerAddUint32(addr *uint32, count int) { 839 for i := 0; i < count; i++ { 840 AddUint32(addr, 1) 841 } 842 } 843 844 func hammerAddUintptr32(uaddr *uint32, count int) { 845 // only safe when uintptr is 32-bit. 846 // not called on 64-bit systems. 847 addr := (*uintptr)(unsafe.Pointer(uaddr)) 848 for i := 0; i < count; i++ { 849 AddUintptr(addr, 1) 850 } 851 } 852 853 func hammerCompareAndSwapInt32(uaddr *uint32, count int) { 854 addr := (*int32)(unsafe.Pointer(uaddr)) 855 for i := 0; i < count; i++ { 856 for { 857 v := *addr 858 if CompareAndSwapInt32(addr, v, v+1) { 859 break 860 } 861 } 862 } 863 } 864 865 func hammerCompareAndSwapUint32(addr *uint32, count int) { 866 for i := 0; i < count; i++ { 867 for { 868 v := *addr 869 if CompareAndSwapUint32(addr, v, v+1) { 870 break 871 } 872 } 873 } 874 } 875 876 func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) { 877 // only safe when uintptr is 32-bit. 878 // not called on 64-bit systems. 879 addr := (*uintptr)(unsafe.Pointer(uaddr)) 880 for i := 0; i < count; i++ { 881 for { 882 v := *addr 883 if CompareAndSwapUintptr(addr, v, v+1) { 884 break 885 } 886 } 887 } 888 } 889 890 func hammerCompareAndSwapPointer32(uaddr *uint32, count int) { 891 // only safe when uintptr is 32-bit. 892 // not called on 64-bit systems. 893 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 894 for i := 0; i < count; i++ { 895 for { 896 v := *addr 897 if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) { 898 break 899 } 900 } 901 } 902 } 903 904 func TestHammer32(t *testing.T) { 905 const p = 4 906 n := 100000 907 if testing.Short() { 908 n = 1000 909 } 910 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 911 912 for name, testf := range hammer32 { 913 c := make(chan int) 914 var val uint32 915 for i := 0; i < p; i++ { 916 go func() { 917 defer func() { 918 if err := recover(); err != nil { 919 t.Error(err.(string)) 920 } 921 c <- 1 922 }() 923 testf(&val, n) 924 }() 925 } 926 for i := 0; i < p; i++ { 927 <-c 928 } 929 if !strings.HasPrefix(name, "Swap") && val != uint32(n)*p { 930 t.Fatalf("%s: val=%d want %d", name, val, n*p) 931 } 932 } 933 } 934 935 var hammer64 = map[string]func(*uint64, int){ 936 "SwapInt64": hammerSwapInt64, 937 "SwapUint64": hammerSwapUint64, 938 "SwapUintptr": hammerSwapUintptr64, 939 "SwapPointer": hammerSwapPointer64, 940 "AddInt64": hammerAddInt64, 941 "AddUint64": hammerAddUint64, 942 "AddUintptr": hammerAddUintptr64, 943 "CompareAndSwapInt64": hammerCompareAndSwapInt64, 944 "CompareAndSwapUint64": hammerCompareAndSwapUint64, 945 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr64, 946 "CompareAndSwapPointer": hammerCompareAndSwapPointer64, 947 } 948 949 func init() { 950 var v uint64 = 1 << 50 951 if uintptr(v) == 0 { 952 // 32-bit system; clear uintptr tests 953 delete(hammer64, "SwapUintptr") 954 delete(hammer64, "SwapPointer") 955 delete(hammer64, "AddUintptr") 956 delete(hammer64, "CompareAndSwapUintptr") 957 delete(hammer64, "CompareAndSwapPointer") 958 } 959 } 960 961 func hammerSwapInt64(uaddr *uint64, count int) { 962 addr := (*int64)(unsafe.Pointer(uaddr)) 963 seed := int(uintptr(unsafe.Pointer(&count))) 964 for i := 0; i < count; i++ { 965 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 966 old := uint64(SwapInt64(addr, int64(new))) 967 if old>>32 != old<<32>>32 { 968 panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) 969 } 970 } 971 } 972 973 func hammerSwapUint64(addr *uint64, count int) { 974 seed := int(uintptr(unsafe.Pointer(&count))) 975 for i := 0; i < count; i++ { 976 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 977 old := SwapUint64(addr, new) 978 if old>>32 != old<<32>>32 { 979 panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) 980 } 981 } 982 } 983 984 func hammerSwapUintptr64(uaddr *uint64, count int) { 985 // only safe when uintptr is 64-bit. 986 // not called on 32-bit systems. 987 addr := (*uintptr)(unsafe.Pointer(uaddr)) 988 seed := int(uintptr(unsafe.Pointer(&count))) 989 for i := 0; i < count; i++ { 990 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 991 old := SwapUintptr(addr, new) 992 if old>>32 != old<<32>>32 { 993 panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) 994 } 995 } 996 } 997 998 func hammerSwapPointer64(uaddr *uint64, count int) { 999 // only safe when uintptr is 64-bit. 1000 // not called on 32-bit systems. 1001 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 1002 seed := int(uintptr(unsafe.Pointer(&count))) 1003 for i := 0; i < count; i++ { 1004 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 1005 old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) 1006 if old>>32 != old<<32>>32 { 1007 panic(fmt.Sprintf("SwapPointer is not atomic: %v", old)) 1008 } 1009 } 1010 } 1011 1012 func hammerAddInt64(uaddr *uint64, count int) { 1013 addr := (*int64)(unsafe.Pointer(uaddr)) 1014 for i := 0; i < count; i++ { 1015 AddInt64(addr, 1) 1016 } 1017 } 1018 1019 func hammerAddUint64(addr *uint64, count int) { 1020 for i := 0; i < count; i++ { 1021 AddUint64(addr, 1) 1022 } 1023 } 1024 1025 func hammerAddUintptr64(uaddr *uint64, count int) { 1026 // only safe when uintptr is 64-bit. 1027 // not called on 32-bit systems. 1028 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1029 for i := 0; i < count; i++ { 1030 AddUintptr(addr, 1) 1031 } 1032 } 1033 1034 func hammerCompareAndSwapInt64(uaddr *uint64, count int) { 1035 addr := (*int64)(unsafe.Pointer(uaddr)) 1036 for i := 0; i < count; i++ { 1037 for { 1038 v := *addr 1039 if CompareAndSwapInt64(addr, v, v+1) { 1040 break 1041 } 1042 } 1043 } 1044 } 1045 1046 func hammerCompareAndSwapUint64(addr *uint64, count int) { 1047 for i := 0; i < count; i++ { 1048 for { 1049 v := *addr 1050 if CompareAndSwapUint64(addr, v, v+1) { 1051 break 1052 } 1053 } 1054 } 1055 } 1056 1057 func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) { 1058 // only safe when uintptr is 64-bit. 1059 // not called on 32-bit systems. 1060 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1061 for i := 0; i < count; i++ { 1062 for { 1063 v := *addr 1064 if CompareAndSwapUintptr(addr, v, v+1) { 1065 break 1066 } 1067 } 1068 } 1069 } 1070 1071 func hammerCompareAndSwapPointer64(uaddr *uint64, count int) { 1072 // only safe when uintptr is 64-bit. 1073 // not called on 32-bit systems. 1074 addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) 1075 for i := 0; i < count; i++ { 1076 for { 1077 v := *addr 1078 if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) { 1079 break 1080 } 1081 } 1082 } 1083 } 1084 1085 func TestHammer64(t *testing.T) { 1086 if test64err != nil { 1087 t.Skipf("Skipping 64-bit tests: %v", test64err) 1088 } 1089 const p = 4 1090 n := 100000 1091 if testing.Short() { 1092 n = 1000 1093 } 1094 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 1095 1096 for name, testf := range hammer64 { 1097 c := make(chan int) 1098 var val uint64 1099 for i := 0; i < p; i++ { 1100 go func() { 1101 defer func() { 1102 if err := recover(); err != nil { 1103 t.Error(err.(string)) 1104 } 1105 c <- 1 1106 }() 1107 testf(&val, n) 1108 }() 1109 } 1110 for i := 0; i < p; i++ { 1111 <-c 1112 } 1113 if !strings.HasPrefix(name, "Swap") && val != uint64(n)*p { 1114 t.Fatalf("%s: val=%d want %d", name, val, n*p) 1115 } 1116 } 1117 } 1118 1119 func hammerStoreLoadInt32(t *testing.T, paddr unsafe.Pointer) { 1120 addr := (*int32)(paddr) 1121 v := LoadInt32(addr) 1122 vlo := v & ((1 << 16) - 1) 1123 vhi := v >> 16 1124 if vlo != vhi { 1125 t.Fatalf("Int32: %#x != %#x", vlo, vhi) 1126 } 1127 new := v + 1 + 1<<16 1128 if vlo == 1e4 { 1129 new = 0 1130 } 1131 StoreInt32(addr, new) 1132 } 1133 1134 func hammerStoreLoadUint32(t *testing.T, paddr unsafe.Pointer) { 1135 addr := (*uint32)(paddr) 1136 v := LoadUint32(addr) 1137 vlo := v & ((1 << 16) - 1) 1138 vhi := v >> 16 1139 if vlo != vhi { 1140 t.Fatalf("Uint32: %#x != %#x", vlo, vhi) 1141 } 1142 new := v + 1 + 1<<16 1143 if vlo == 1e4 { 1144 new = 0 1145 } 1146 StoreUint32(addr, new) 1147 } 1148 1149 func hammerStoreLoadInt64(t *testing.T, paddr unsafe.Pointer) { 1150 addr := (*int64)(paddr) 1151 v := LoadInt64(addr) 1152 vlo := v & ((1 << 32) - 1) 1153 vhi := v >> 32 1154 if vlo != vhi { 1155 t.Fatalf("Int64: %#x != %#x", vlo, vhi) 1156 } 1157 new := v + 1 + 1<<32 1158 StoreInt64(addr, new) 1159 } 1160 1161 func hammerStoreLoadUint64(t *testing.T, paddr unsafe.Pointer) { 1162 addr := (*uint64)(paddr) 1163 v := LoadUint64(addr) 1164 vlo := v & ((1 << 32) - 1) 1165 vhi := v >> 32 1166 if vlo != vhi { 1167 t.Fatalf("Uint64: %#x != %#x", vlo, vhi) 1168 } 1169 new := v + 1 + 1<<32 1170 StoreUint64(addr, new) 1171 } 1172 1173 func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) { 1174 addr := (*uintptr)(paddr) 1175 var test64 uint64 = 1 << 50 1176 arch32 := uintptr(test64) == 0 1177 v := LoadUintptr(addr) 1178 new := v 1179 if arch32 { 1180 vlo := v & ((1 << 16) - 1) 1181 vhi := v >> 16 1182 if vlo != vhi { 1183 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 1184 } 1185 new = v + 1 + 1<<16 1186 if vlo == 1e4 { 1187 new = 0 1188 } 1189 } else { 1190 vlo := v & ((1 << 32) - 1) 1191 vhi := v >> 32 1192 if vlo != vhi { 1193 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 1194 } 1195 inc := uint64(1 + 1<<32) 1196 new = v + uintptr(inc) 1197 } 1198 StoreUintptr(addr, new) 1199 } 1200 1201 func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) { 1202 addr := (*unsafe.Pointer)(paddr) 1203 var test64 uint64 = 1 << 50 1204 arch32 := uintptr(test64) == 0 1205 v := uintptr(LoadPointer(addr)) 1206 new := v 1207 if arch32 { 1208 vlo := v & ((1 << 16) - 1) 1209 vhi := v >> 16 1210 if vlo != vhi { 1211 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 1212 } 1213 new = v + 1 + 1<<16 1214 if vlo == 1e4 { 1215 new = 0 1216 } 1217 } else { 1218 vlo := v & ((1 << 32) - 1) 1219 vhi := v >> 32 1220 if vlo != vhi { 1221 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 1222 } 1223 inc := uint64(1 + 1<<32) 1224 new = v + uintptr(inc) 1225 } 1226 StorePointer(addr, unsafe.Pointer(new)) 1227 } 1228 1229 func TestHammerStoreLoad(t *testing.T) { 1230 var tests []func(*testing.T, unsafe.Pointer) 1231 tests = append(tests, hammerStoreLoadInt32, hammerStoreLoadUint32, 1232 hammerStoreLoadUintptr, hammerStoreLoadPointer) 1233 if test64err == nil { 1234 tests = append(tests, hammerStoreLoadInt64, hammerStoreLoadUint64) 1235 } 1236 n := int(1e6) 1237 if testing.Short() { 1238 n = int(1e4) 1239 } 1240 const procs = 8 1241 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs)) 1242 for _, tt := range tests { 1243 c := make(chan int) 1244 var val uint64 1245 for p := 0; p < procs; p++ { 1246 go func() { 1247 for i := 0; i < n; i++ { 1248 tt(t, unsafe.Pointer(&val)) 1249 } 1250 c <- 1 1251 }() 1252 } 1253 for p := 0; p < procs; p++ { 1254 <-c 1255 } 1256 } 1257 } 1258 1259 func TestStoreLoadSeqCst32(t *testing.T) { 1260 if runtime.NumCPU() == 1 { 1261 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1262 } 1263 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1264 N := int32(1e3) 1265 if testing.Short() { 1266 N = int32(1e2) 1267 } 1268 c := make(chan bool, 2) 1269 X := [2]int32{} 1270 ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}} 1271 for p := 0; p < 2; p++ { 1272 go func(me int) { 1273 he := 1 - me 1274 for i := int32(1); i < N; i++ { 1275 StoreInt32(&X[me], i) 1276 my := LoadInt32(&X[he]) 1277 StoreInt32(&ack[me][i%3], my) 1278 for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ { 1279 if w%1000 == 0 { 1280 runtime.Gosched() 1281 } 1282 } 1283 his := LoadInt32(&ack[he][i%3]) 1284 if (my != i && my != i-1) || (his != i && his != i-1) { 1285 t.Fatalf("invalid values: %d/%d (%d)", my, his, i) 1286 } 1287 if my != i && his != i { 1288 t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 1289 } 1290 StoreInt32(&ack[me][(i-1)%3], -1) 1291 } 1292 c <- true 1293 }(p) 1294 } 1295 <-c 1296 <-c 1297 } 1298 1299 func TestStoreLoadSeqCst64(t *testing.T) { 1300 if runtime.NumCPU() == 1 { 1301 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1302 } 1303 if test64err != nil { 1304 t.Skipf("Skipping 64-bit tests: %v", test64err) 1305 } 1306 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1307 N := int64(1e3) 1308 if testing.Short() { 1309 N = int64(1e2) 1310 } 1311 c := make(chan bool, 2) 1312 X := [2]int64{} 1313 ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}} 1314 for p := 0; p < 2; p++ { 1315 go func(me int) { 1316 he := 1 - me 1317 for i := int64(1); i < N; i++ { 1318 StoreInt64(&X[me], i) 1319 my := LoadInt64(&X[he]) 1320 StoreInt64(&ack[me][i%3], my) 1321 for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ { 1322 if w%1000 == 0 { 1323 runtime.Gosched() 1324 } 1325 } 1326 his := LoadInt64(&ack[he][i%3]) 1327 if (my != i && my != i-1) || (his != i && his != i-1) { 1328 t.Fatalf("invalid values: %d/%d (%d)", my, his, i) 1329 } 1330 if my != i && his != i { 1331 t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 1332 } 1333 StoreInt64(&ack[me][(i-1)%3], -1) 1334 } 1335 c <- true 1336 }(p) 1337 } 1338 <-c 1339 <-c 1340 } 1341 1342 func TestStoreLoadRelAcq32(t *testing.T) { 1343 if runtime.NumCPU() == 1 { 1344 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1345 } 1346 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1347 N := int32(1e3) 1348 if testing.Short() { 1349 N = int32(1e2) 1350 } 1351 c := make(chan bool, 2) 1352 type Data struct { 1353 signal int32 1354 pad1 [128]int8 1355 data1 int32 1356 pad2 [128]int8 1357 data2 float32 1358 } 1359 var X Data 1360 for p := int32(0); p < 2; p++ { 1361 go func(p int32) { 1362 for i := int32(1); i < N; i++ { 1363 if (i+p)%2 == 0 { 1364 X.data1 = i 1365 X.data2 = float32(i) 1366 StoreInt32(&X.signal, i) 1367 } else { 1368 for w := 1; LoadInt32(&X.signal) != i; w++ { 1369 if w%1000 == 0 { 1370 runtime.Gosched() 1371 } 1372 } 1373 d1 := X.data1 1374 d2 := X.data2 1375 if d1 != i || d2 != float32(i) { 1376 t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i) 1377 } 1378 } 1379 } 1380 c <- true 1381 }(p) 1382 } 1383 <-c 1384 <-c 1385 } 1386 1387 func TestStoreLoadRelAcq64(t *testing.T) { 1388 if runtime.NumCPU() == 1 { 1389 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 1390 } 1391 if test64err != nil { 1392 t.Skipf("Skipping 64-bit tests: %v", test64err) 1393 } 1394 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 1395 N := int64(1e3) 1396 if testing.Short() { 1397 N = int64(1e2) 1398 } 1399 c := make(chan bool, 2) 1400 type Data struct { 1401 signal int64 1402 pad1 [128]int8 1403 data1 int64 1404 pad2 [128]int8 1405 data2 float64 1406 } 1407 var X Data 1408 for p := int64(0); p < 2; p++ { 1409 go func(p int64) { 1410 for i := int64(1); i < N; i++ { 1411 if (i+p)%2 == 0 { 1412 X.data1 = i 1413 X.data2 = float64(i) 1414 StoreInt64(&X.signal, i) 1415 } else { 1416 for w := 1; LoadInt64(&X.signal) != i; w++ { 1417 if w%1000 == 0 { 1418 runtime.Gosched() 1419 } 1420 } 1421 d1 := X.data1 1422 d2 := X.data2 1423 if d1 != i || d2 != float64(i) { 1424 t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i) 1425 } 1426 } 1427 } 1428 c <- true 1429 }(p) 1430 } 1431 <-c 1432 <-c 1433 } 1434 1435 func shouldPanic(t *testing.T, name string, f func()) { 1436 defer func() { 1437 if recover() == nil { 1438 t.Errorf("%s did not panic", name) 1439 } 1440 }() 1441 f() 1442 } 1443 1444 func TestUnaligned64(t *testing.T) { 1445 // Unaligned 64-bit atomics on 32-bit systems are 1446 // a continual source of pain. Test that on 32-bit systems they crash 1447 // instead of failing silently. 1448 if unsafe.Sizeof(int(0)) != 4 { 1449 t.Skip("test only runs on 32-bit systems") 1450 } 1451 1452 x := make([]uint32, 4) 1453 p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned 1454 1455 shouldPanic(t, "LoadUint64", func() { LoadUint64(p) }) 1456 shouldPanic(t, "StoreUint64", func() { StoreUint64(p, 1) }) 1457 shouldPanic(t, "CompareAndSwapUint64", func() { CompareAndSwapUint64(p, 1, 2) }) 1458 shouldPanic(t, "AddUint64", func() { AddUint64(p, 3) }) 1459 } 1460 1461 func TestNilDeref(t *testing.T) { 1462 funcs := [...]func(){ 1463 func() { CompareAndSwapInt32(nil, 0, 0) }, 1464 func() { CompareAndSwapInt64(nil, 0, 0) }, 1465 func() { CompareAndSwapUint32(nil, 0, 0) }, 1466 func() { CompareAndSwapUint64(nil, 0, 0) }, 1467 func() { CompareAndSwapUintptr(nil, 0, 0) }, 1468 func() { CompareAndSwapPointer(nil, nil, nil) }, 1469 func() { SwapInt32(nil, 0) }, 1470 func() { SwapUint32(nil, 0) }, 1471 func() { SwapInt64(nil, 0) }, 1472 func() { SwapUint64(nil, 0) }, 1473 func() { SwapUintptr(nil, 0) }, 1474 func() { SwapPointer(nil, nil) }, 1475 func() { AddInt32(nil, 0) }, 1476 func() { AddUint32(nil, 0) }, 1477 func() { AddInt64(nil, 0) }, 1478 func() { AddUint64(nil, 0) }, 1479 func() { AddUintptr(nil, 0) }, 1480 func() { LoadInt32(nil) }, 1481 func() { LoadInt64(nil) }, 1482 func() { LoadUint32(nil) }, 1483 func() { LoadUint64(nil) }, 1484 func() { LoadUintptr(nil) }, 1485 func() { LoadPointer(nil) }, 1486 func() { StoreInt32(nil, 0) }, 1487 func() { StoreInt64(nil, 0) }, 1488 func() { StoreUint32(nil, 0) }, 1489 func() { StoreUint64(nil, 0) }, 1490 func() { StoreUintptr(nil, 0) }, 1491 func() { StorePointer(nil, nil) }, 1492 } 1493 for _, f := range funcs { 1494 func() { 1495 defer func() { 1496 runtime.GC() 1497 recover() 1498 }() 1499 f() 1500 }() 1501 } 1502 }