github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 "reflect" 10 "runtime" 11 "runtime/debug" 12 "strings" 13 . "sync/atomic" 14 "testing" 15 "unsafe" 16 ) 17 18 // Tests of correct behavior, without contention. 19 // (Does the function work as advertised?) 20 // 21 // Test that the Add functions add correctly. 22 // Test that the CompareAndSwap functions actually 23 // do the comparison and the swap correctly. 24 // 25 // The loop over power-of-two values is meant to 26 // ensure that the operations apply to the full word size. 27 // The struct fields x.before and x.after check that the 28 // operations do not extend past the full word size. 29 30 const ( 31 magic32 = 0xdedbeef 32 magic64 = 0xdeddeadbeefbeef 33 ) 34 35 func TestSwapInt32(t *testing.T) { 36 var x struct { 37 before int32 38 i int32 39 after int32 40 } 41 x.before = magic32 42 x.after = magic32 43 var j int32 44 for delta := int32(1); delta+delta > delta; delta += delta { 45 k := SwapInt32(&x.i, delta) 46 if x.i != delta || k != j { 47 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 48 } 49 j = delta 50 } 51 if x.before != magic32 || x.after != magic32 { 52 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 53 } 54 } 55 56 func TestSwapInt32Method(t *testing.T) { 57 var x struct { 58 before int32 59 i Int32 60 after int32 61 } 62 x.before = magic32 63 x.after = magic32 64 var j int32 65 for delta := int32(1); delta+delta > delta; delta += delta { 66 k := x.i.Swap(delta) 67 if x.i.Load() != delta || k != j { 68 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 69 } 70 j = delta 71 } 72 if x.before != magic32 || x.after != magic32 { 73 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 74 } 75 } 76 77 func TestSwapUint32(t *testing.T) { 78 var x struct { 79 before uint32 80 i uint32 81 after uint32 82 } 83 x.before = magic32 84 x.after = magic32 85 var j uint32 86 for delta := uint32(1); delta+delta > delta; delta += delta { 87 k := SwapUint32(&x.i, delta) 88 if x.i != delta || k != j { 89 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 90 } 91 j = delta 92 } 93 if x.before != magic32 || x.after != magic32 { 94 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 95 } 96 } 97 98 func TestSwapUint32Method(t *testing.T) { 99 var x struct { 100 before uint32 101 i Uint32 102 after uint32 103 } 104 x.before = magic32 105 x.after = magic32 106 var j uint32 107 for delta := uint32(1); delta+delta > delta; delta += delta { 108 k := x.i.Swap(delta) 109 if x.i.Load() != delta || k != j { 110 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 111 } 112 j = delta 113 } 114 if x.before != magic32 || x.after != magic32 { 115 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 116 } 117 } 118 119 func TestSwapInt64(t *testing.T) { 120 var x struct { 121 before int64 122 i int64 123 after int64 124 } 125 magic64 := int64(magic64) 126 x.before = magic64 127 x.after = magic64 128 var j int64 129 for delta := int64(1); delta+delta > delta; delta += delta { 130 k := SwapInt64(&x.i, delta) 131 if x.i != delta || k != j { 132 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 133 } 134 j = delta 135 } 136 if x.before != magic64 || x.after != magic64 { 137 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 138 } 139 } 140 141 func TestSwapInt64Method(t *testing.T) { 142 var x struct { 143 before int64 144 i Int64 145 after int64 146 } 147 magic64 := int64(magic64) 148 x.before = magic64 149 x.after = magic64 150 var j int64 151 for delta := int64(1); delta+delta > delta; delta += delta { 152 k := x.i.Swap(delta) 153 if x.i.Load() != delta || k != j { 154 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 155 } 156 j = delta 157 } 158 if x.before != magic64 || x.after != magic64 { 159 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 160 } 161 } 162 163 func TestSwapUint64(t *testing.T) { 164 var x struct { 165 before uint64 166 i uint64 167 after uint64 168 } 169 magic64 := uint64(magic64) 170 x.before = magic64 171 x.after = magic64 172 var j uint64 173 for delta := uint64(1); delta+delta > delta; delta += delta { 174 k := SwapUint64(&x.i, delta) 175 if x.i != delta || k != j { 176 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 177 } 178 j = delta 179 } 180 if x.before != magic64 || x.after != magic64 { 181 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 182 } 183 } 184 185 func TestSwapUint64Method(t *testing.T) { 186 var x struct { 187 before uint64 188 i Uint64 189 after uint64 190 } 191 magic64 := uint64(magic64) 192 x.before = magic64 193 x.after = magic64 194 var j uint64 195 for delta := uint64(1); delta+delta > delta; delta += delta { 196 k := x.i.Swap(delta) 197 if x.i.Load() != delta || k != j { 198 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 199 } 200 j = delta 201 } 202 if x.before != magic64 || x.after != magic64 { 203 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 204 } 205 } 206 207 func TestSwapUintptr(t *testing.T) { 208 var x struct { 209 before uintptr 210 i uintptr 211 after uintptr 212 } 213 var m uint64 = magic64 214 magicptr := uintptr(m) 215 x.before = magicptr 216 x.after = magicptr 217 var j uintptr 218 for delta := uintptr(1); delta+delta > delta; delta += delta { 219 k := SwapUintptr(&x.i, delta) 220 if x.i != delta || k != j { 221 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 222 } 223 j = delta 224 } 225 if x.before != magicptr || x.after != magicptr { 226 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 227 } 228 } 229 230 func TestSwapUintptrMethod(t *testing.T) { 231 var x struct { 232 before uintptr 233 i Uintptr 234 after uintptr 235 } 236 var m uint64 = magic64 237 magicptr := uintptr(m) 238 x.before = magicptr 239 x.after = magicptr 240 var j uintptr 241 for delta := uintptr(1); delta+delta > delta; delta += delta { 242 k := x.i.Swap(delta) 243 if x.i.Load() != delta || k != j { 244 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 245 } 246 j = delta 247 } 248 if x.before != magicptr || x.after != magicptr { 249 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 250 } 251 } 252 253 var global [1024]byte 254 255 func testPointers() []unsafe.Pointer { 256 var pointers []unsafe.Pointer 257 // globals 258 for i := 0; i < 10; i++ { 259 pointers = append(pointers, unsafe.Pointer(&global[1<<i-1])) 260 } 261 // heap 262 pointers = append(pointers, unsafe.Pointer(new(byte))) 263 // nil 264 pointers = append(pointers, nil) 265 return pointers 266 } 267 268 func TestSwapPointer(t *testing.T) { 269 var x struct { 270 before uintptr 271 i unsafe.Pointer 272 after uintptr 273 } 274 var m uint64 = magic64 275 magicptr := uintptr(m) 276 x.before = magicptr 277 x.after = magicptr 278 var j unsafe.Pointer 279 280 for _, p := range testPointers() { 281 k := SwapPointer(&x.i, p) 282 if x.i != p || k != j { 283 t.Fatalf("p=%p i=%p j=%p k=%p", p, x.i, j, k) 284 } 285 j = p 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 TestSwapPointerMethod(t *testing.T) { 293 var x struct { 294 before uintptr 295 i Pointer[byte] 296 after uintptr 297 } 298 var m uint64 = magic64 299 magicptr := uintptr(m) 300 x.before = magicptr 301 x.after = magicptr 302 var j *byte 303 for _, p := range testPointers() { 304 p := (*byte)(p) 305 k := x.i.Swap(p) 306 if x.i.Load() != p || k != j { 307 t.Fatalf("p=%p i=%p j=%p k=%p", p, x.i.Load(), j, k) 308 } 309 j = p 310 } 311 if x.before != magicptr || x.after != magicptr { 312 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 313 } 314 } 315 316 func TestAddInt32(t *testing.T) { 317 var x struct { 318 before int32 319 i int32 320 after int32 321 } 322 x.before = magic32 323 x.after = magic32 324 var j int32 325 for delta := int32(1); delta+delta > delta; delta += delta { 326 k := AddInt32(&x.i, delta) 327 j += delta 328 if x.i != j || k != j { 329 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 330 } 331 } 332 if x.before != magic32 || x.after != magic32 { 333 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 334 } 335 } 336 337 func TestAddInt32Method(t *testing.T) { 338 var x struct { 339 before int32 340 i Int32 341 after int32 342 } 343 x.before = magic32 344 x.after = magic32 345 var j int32 346 for delta := int32(1); delta+delta > delta; delta += delta { 347 k := x.i.Add(delta) 348 j += delta 349 if x.i.Load() != j || k != j { 350 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 351 } 352 } 353 if x.before != magic32 || x.after != magic32 { 354 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 355 } 356 } 357 358 func TestAddUint32(t *testing.T) { 359 var x struct { 360 before uint32 361 i uint32 362 after uint32 363 } 364 x.before = magic32 365 x.after = magic32 366 var j uint32 367 for delta := uint32(1); delta+delta > delta; delta += delta { 368 k := AddUint32(&x.i, delta) 369 j += delta 370 if x.i != j || k != j { 371 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 372 } 373 } 374 if x.before != magic32 || x.after != magic32 { 375 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 376 } 377 } 378 379 func TestAddUint32Method(t *testing.T) { 380 var x struct { 381 before uint32 382 i Uint32 383 after uint32 384 } 385 x.before = magic32 386 x.after = magic32 387 var j uint32 388 for delta := uint32(1); delta+delta > delta; delta += delta { 389 k := x.i.Add(delta) 390 j += delta 391 if x.i.Load() != j || k != j { 392 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 393 } 394 } 395 if x.before != magic32 || x.after != magic32 { 396 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 397 } 398 } 399 400 func TestAddInt64(t *testing.T) { 401 var x struct { 402 before int64 403 i int64 404 after int64 405 } 406 magic64 := int64(magic64) 407 x.before = magic64 408 x.after = magic64 409 var j int64 410 for delta := int64(1); delta+delta > delta; delta += delta { 411 k := AddInt64(&x.i, delta) 412 j += delta 413 if x.i != j || k != j { 414 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 415 } 416 } 417 if x.before != magic64 || x.after != magic64 { 418 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 419 } 420 } 421 422 func TestAddInt64Method(t *testing.T) { 423 var x struct { 424 before int64 425 i Int64 426 after int64 427 } 428 magic64 := int64(magic64) 429 x.before = magic64 430 x.after = magic64 431 var j int64 432 for delta := int64(1); delta+delta > delta; delta += delta { 433 k := x.i.Add(delta) 434 j += delta 435 if x.i.Load() != j || k != j { 436 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 437 } 438 } 439 if x.before != magic64 || x.after != magic64 { 440 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 441 } 442 } 443 444 func TestAddUint64(t *testing.T) { 445 var x struct { 446 before uint64 447 i uint64 448 after uint64 449 } 450 magic64 := uint64(magic64) 451 x.before = magic64 452 x.after = magic64 453 var j uint64 454 for delta := uint64(1); delta+delta > delta; delta += delta { 455 k := AddUint64(&x.i, delta) 456 j += delta 457 if x.i != j || k != j { 458 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 459 } 460 } 461 if x.before != magic64 || x.after != magic64 { 462 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 463 } 464 } 465 466 func TestAddUint64Method(t *testing.T) { 467 var x struct { 468 before uint64 469 i Uint64 470 after uint64 471 } 472 magic64 := uint64(magic64) 473 x.before = magic64 474 x.after = magic64 475 var j uint64 476 for delta := uint64(1); delta+delta > delta; delta += delta { 477 k := x.i.Add(delta) 478 j += delta 479 if x.i.Load() != j || k != j { 480 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 481 } 482 } 483 if x.before != magic64 || x.after != magic64 { 484 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 485 } 486 } 487 488 func TestAddUintptr(t *testing.T) { 489 var x struct { 490 before uintptr 491 i uintptr 492 after uintptr 493 } 494 var m uint64 = magic64 495 magicptr := uintptr(m) 496 x.before = magicptr 497 x.after = magicptr 498 var j uintptr 499 for delta := uintptr(1); delta+delta > delta; delta += delta { 500 k := AddUintptr(&x.i, delta) 501 j += delta 502 if x.i != j || k != j { 503 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) 504 } 505 } 506 if x.before != magicptr || x.after != magicptr { 507 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 508 } 509 } 510 511 func TestAddUintptrMethod(t *testing.T) { 512 var x struct { 513 before uintptr 514 i Uintptr 515 after uintptr 516 } 517 var m uint64 = magic64 518 magicptr := uintptr(m) 519 x.before = magicptr 520 x.after = magicptr 521 var j uintptr 522 for delta := uintptr(1); delta+delta > delta; delta += delta { 523 k := x.i.Add(delta) 524 j += delta 525 if x.i.Load() != j || k != j { 526 t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i.Load(), j, k) 527 } 528 } 529 if x.before != magicptr || x.after != magicptr { 530 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 531 } 532 } 533 534 func TestCompareAndSwapInt32(t *testing.T) { 535 var x struct { 536 before int32 537 i int32 538 after int32 539 } 540 x.before = magic32 541 x.after = magic32 542 for val := int32(1); val+val > val; val += val { 543 x.i = val 544 if !CompareAndSwapInt32(&x.i, val, val+1) { 545 t.Fatalf("should have swapped %#x %#x", val, val+1) 546 } 547 if x.i != val+1 { 548 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 549 } 550 x.i = val + 1 551 if CompareAndSwapInt32(&x.i, val, val+2) { 552 t.Fatalf("should not have swapped %#x %#x", val, val+2) 553 } 554 if x.i != val+1 { 555 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 556 } 557 } 558 if x.before != magic32 || x.after != magic32 { 559 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 560 } 561 } 562 563 func TestCompareAndSwapInt32Method(t *testing.T) { 564 var x struct { 565 before int32 566 i Int32 567 after int32 568 } 569 x.before = magic32 570 x.after = magic32 571 for val := int32(1); val+val > val; val += val { 572 x.i.Store(val) 573 if !x.i.CompareAndSwap(val, val+1) { 574 t.Fatalf("should have swapped %#x %#x", val, val+1) 575 } 576 if x.i.Load() != val+1 { 577 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 578 } 579 x.i.Store(val + 1) 580 if x.i.CompareAndSwap(val, val+2) { 581 t.Fatalf("should not have swapped %#x %#x", val, val+2) 582 } 583 if x.i.Load() != val+1 { 584 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 585 } 586 } 587 if x.before != magic32 || x.after != magic32 { 588 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 589 } 590 } 591 592 func TestCompareAndSwapUint32(t *testing.T) { 593 var x struct { 594 before uint32 595 i uint32 596 after uint32 597 } 598 x.before = magic32 599 x.after = magic32 600 for val := uint32(1); val+val > val; val += val { 601 x.i = val 602 if !CompareAndSwapUint32(&x.i, val, val+1) { 603 t.Fatalf("should have swapped %#x %#x", val, val+1) 604 } 605 if x.i != val+1 { 606 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 607 } 608 x.i = val + 1 609 if CompareAndSwapUint32(&x.i, val, val+2) { 610 t.Fatalf("should not have swapped %#x %#x", val, val+2) 611 } 612 if x.i != val+1 { 613 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 614 } 615 } 616 if x.before != magic32 || x.after != magic32 { 617 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 618 } 619 } 620 621 func TestCompareAndSwapUint32Method(t *testing.T) { 622 var x struct { 623 before uint32 624 i Uint32 625 after uint32 626 } 627 x.before = magic32 628 x.after = magic32 629 for val := uint32(1); val+val > val; val += val { 630 x.i.Store(val) 631 if !x.i.CompareAndSwap(val, val+1) { 632 t.Fatalf("should have swapped %#x %#x", val, val+1) 633 } 634 if x.i.Load() != val+1 { 635 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 636 } 637 x.i.Store(val + 1) 638 if x.i.CompareAndSwap(val, val+2) { 639 t.Fatalf("should not have swapped %#x %#x", val, val+2) 640 } 641 if x.i.Load() != val+1 { 642 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 643 } 644 } 645 if x.before != magic32 || x.after != magic32 { 646 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 647 } 648 } 649 650 func TestCompareAndSwapInt64(t *testing.T) { 651 var x struct { 652 before int64 653 i int64 654 after int64 655 } 656 magic64 := int64(magic64) 657 x.before = magic64 658 x.after = magic64 659 for val := int64(1); val+val > val; val += val { 660 x.i = val 661 if !CompareAndSwapInt64(&x.i, val, val+1) { 662 t.Fatalf("should have swapped %#x %#x", val, val+1) 663 } 664 if x.i != val+1 { 665 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 666 } 667 x.i = val + 1 668 if CompareAndSwapInt64(&x.i, val, val+2) { 669 t.Fatalf("should not have swapped %#x %#x", val, val+2) 670 } 671 if x.i != val+1 { 672 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 673 } 674 } 675 if x.before != magic64 || x.after != magic64 { 676 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 677 } 678 } 679 680 func TestCompareAndSwapInt64Method(t *testing.T) { 681 var x struct { 682 before int64 683 i Int64 684 after int64 685 } 686 magic64 := int64(magic64) 687 x.before = magic64 688 x.after = magic64 689 for val := int64(1); val+val > val; val += val { 690 x.i.Store(val) 691 if !x.i.CompareAndSwap(val, val+1) { 692 t.Fatalf("should have swapped %#x %#x", val, val+1) 693 } 694 if x.i.Load() != val+1 { 695 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 696 } 697 x.i.Store(val + 1) 698 if x.i.CompareAndSwap(val, val+2) { 699 t.Fatalf("should not have swapped %#x %#x", val, val+2) 700 } 701 if x.i.Load() != val+1 { 702 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 703 } 704 } 705 if x.before != magic64 || x.after != magic64 { 706 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 707 } 708 } 709 710 func testCompareAndSwapUint64(t *testing.T, cas func(*uint64, uint64, uint64) bool) { 711 var x struct { 712 before uint64 713 i uint64 714 after uint64 715 } 716 magic64 := uint64(magic64) 717 x.before = magic64 718 x.after = magic64 719 for val := uint64(1); val+val > val; val += val { 720 x.i = val 721 if !cas(&x.i, val, val+1) { 722 t.Fatalf("should have swapped %#x %#x", val, val+1) 723 } 724 if x.i != val+1 { 725 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 726 } 727 x.i = val + 1 728 if cas(&x.i, val, val+2) { 729 t.Fatalf("should not have swapped %#x %#x", val, val+2) 730 } 731 if x.i != val+1 { 732 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 733 } 734 } 735 if x.before != magic64 || x.after != magic64 { 736 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 737 } 738 } 739 740 func TestCompareAndSwapUint64(t *testing.T) { 741 testCompareAndSwapUint64(t, CompareAndSwapUint64) 742 } 743 744 func TestCompareAndSwapUint64Method(t *testing.T) { 745 var x struct { 746 before uint64 747 i Uint64 748 after uint64 749 } 750 magic64 := uint64(magic64) 751 x.before = magic64 752 x.after = magic64 753 for val := uint64(1); val+val > val; val += val { 754 x.i.Store(val) 755 if !x.i.CompareAndSwap(val, val+1) { 756 t.Fatalf("should have swapped %#x %#x", val, val+1) 757 } 758 if x.i.Load() != val+1 { 759 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 760 } 761 x.i.Store(val + 1) 762 if x.i.CompareAndSwap(val, val+2) { 763 t.Fatalf("should not have swapped %#x %#x", val, val+2) 764 } 765 if x.i.Load() != val+1 { 766 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 767 } 768 } 769 if x.before != magic64 || x.after != magic64 { 770 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 771 } 772 } 773 774 func TestCompareAndSwapUintptr(t *testing.T) { 775 var x struct { 776 before uintptr 777 i uintptr 778 after uintptr 779 } 780 var m uint64 = magic64 781 magicptr := uintptr(m) 782 x.before = magicptr 783 x.after = magicptr 784 for val := uintptr(1); val+val > val; val += val { 785 x.i = val 786 if !CompareAndSwapUintptr(&x.i, val, val+1) { 787 t.Fatalf("should have swapped %#x %#x", val, val+1) 788 } 789 if x.i != val+1 { 790 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 791 } 792 x.i = val + 1 793 if CompareAndSwapUintptr(&x.i, val, val+2) { 794 t.Fatalf("should not have swapped %#x %#x", val, val+2) 795 } 796 if x.i != val+1 { 797 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1) 798 } 799 } 800 if x.before != magicptr || x.after != magicptr { 801 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 802 } 803 } 804 805 func TestCompareAndSwapUintptrMethod(t *testing.T) { 806 var x struct { 807 before uintptr 808 i Uintptr 809 after uintptr 810 } 811 var m uint64 = magic64 812 magicptr := uintptr(m) 813 x.before = magicptr 814 x.after = magicptr 815 for val := uintptr(1); val+val > val; val += val { 816 x.i.Store(val) 817 if !x.i.CompareAndSwap(val, val+1) { 818 t.Fatalf("should have swapped %#x %#x", val, val+1) 819 } 820 if x.i.Load() != val+1 { 821 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 822 } 823 x.i.Store(val + 1) 824 if x.i.CompareAndSwap(val, val+2) { 825 t.Fatalf("should not have swapped %#x %#x", val, val+2) 826 } 827 if x.i.Load() != val+1 { 828 t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i.Load(), val+1) 829 } 830 } 831 if x.before != magicptr || x.after != magicptr { 832 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uintptr(magicptr), uintptr(magicptr)) 833 } 834 } 835 836 func TestCompareAndSwapPointer(t *testing.T) { 837 var x struct { 838 before uintptr 839 i unsafe.Pointer 840 after uintptr 841 } 842 var m uint64 = magic64 843 magicptr := uintptr(m) 844 x.before = magicptr 845 x.after = magicptr 846 q := unsafe.Pointer(new(byte)) 847 for _, p := range testPointers() { 848 x.i = p 849 if !CompareAndSwapPointer(&x.i, p, q) { 850 t.Fatalf("should have swapped %p %p", p, q) 851 } 852 if x.i != q { 853 t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) 854 } 855 if CompareAndSwapPointer(&x.i, p, nil) { 856 t.Fatalf("should not have swapped %p nil", p) 857 } 858 if x.i != q { 859 t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i, q) 860 } 861 } 862 if x.before != magicptr || x.after != magicptr { 863 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 864 } 865 } 866 867 func TestCompareAndSwapPointerMethod(t *testing.T) { 868 var x struct { 869 before uintptr 870 i Pointer[byte] 871 after uintptr 872 } 873 var m uint64 = magic64 874 magicptr := uintptr(m) 875 x.before = magicptr 876 x.after = magicptr 877 q := new(byte) 878 for _, p := range testPointers() { 879 p := (*byte)(p) 880 x.i.Store(p) 881 if !x.i.CompareAndSwap(p, q) { 882 t.Fatalf("should have swapped %p %p", p, q) 883 } 884 if x.i.Load() != q { 885 t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i.Load(), q) 886 } 887 if x.i.CompareAndSwap(p, nil) { 888 t.Fatalf("should not have swapped %p nil", p) 889 } 890 if x.i.Load() != q { 891 t.Fatalf("wrong x.i after swap: x.i=%p want %p", x.i.Load(), q) 892 } 893 } 894 if x.before != magicptr || x.after != magicptr { 895 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 896 } 897 } 898 899 func TestLoadInt32(t *testing.T) { 900 var x struct { 901 before int32 902 i int32 903 after int32 904 } 905 x.before = magic32 906 x.after = magic32 907 for delta := int32(1); delta+delta > delta; delta += delta { 908 k := LoadInt32(&x.i) 909 if k != x.i { 910 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 911 } 912 x.i += delta 913 } 914 if x.before != magic32 || x.after != magic32 { 915 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 916 } 917 } 918 919 func TestLoadInt32Method(t *testing.T) { 920 var x struct { 921 before int32 922 i Int32 923 after int32 924 } 925 x.before = magic32 926 x.after = magic32 927 want := int32(0) 928 for delta := int32(1); delta+delta > delta; delta += delta { 929 k := x.i.Load() 930 if k != want { 931 t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) 932 } 933 x.i.Store(k + delta) 934 want = k + delta 935 } 936 if x.before != magic32 || x.after != magic32 { 937 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 938 } 939 } 940 941 func TestLoadUint32(t *testing.T) { 942 var x struct { 943 before uint32 944 i uint32 945 after uint32 946 } 947 x.before = magic32 948 x.after = magic32 949 for delta := uint32(1); delta+delta > delta; delta += delta { 950 k := LoadUint32(&x.i) 951 if k != x.i { 952 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 953 } 954 x.i += delta 955 } 956 if x.before != magic32 || x.after != magic32 { 957 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 958 } 959 } 960 961 func TestLoadUint32Method(t *testing.T) { 962 var x struct { 963 before uint32 964 i Uint32 965 after uint32 966 } 967 x.before = magic32 968 x.after = magic32 969 want := uint32(0) 970 for delta := uint32(1); delta+delta > delta; delta += delta { 971 k := x.i.Load() 972 if k != want { 973 t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) 974 } 975 x.i.Store(k + delta) 976 want = k + delta 977 } 978 if x.before != magic32 || x.after != magic32 { 979 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 980 } 981 } 982 983 func TestLoadInt64(t *testing.T) { 984 var x struct { 985 before int64 986 i int64 987 after int64 988 } 989 magic64 := int64(magic64) 990 x.before = magic64 991 x.after = magic64 992 for delta := int64(1); delta+delta > delta; delta += delta { 993 k := LoadInt64(&x.i) 994 if k != x.i { 995 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 996 } 997 x.i += delta 998 } 999 if x.before != magic64 || x.after != magic64 { 1000 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1001 } 1002 } 1003 1004 func TestLoadInt64Method(t *testing.T) { 1005 var x struct { 1006 before int64 1007 i Int64 1008 after int64 1009 } 1010 magic64 := int64(magic64) 1011 x.before = magic64 1012 x.after = magic64 1013 want := int64(0) 1014 for delta := int64(1); delta+delta > delta; delta += delta { 1015 k := x.i.Load() 1016 if k != want { 1017 t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) 1018 } 1019 x.i.Store(k + delta) 1020 want = k + delta 1021 } 1022 if x.before != magic64 || x.after != magic64 { 1023 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1024 } 1025 } 1026 1027 func TestLoadUint64(t *testing.T) { 1028 var x struct { 1029 before uint64 1030 i uint64 1031 after uint64 1032 } 1033 magic64 := uint64(magic64) 1034 x.before = magic64 1035 x.after = magic64 1036 for delta := uint64(1); delta+delta > delta; delta += delta { 1037 k := LoadUint64(&x.i) 1038 if k != x.i { 1039 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 1040 } 1041 x.i += delta 1042 } 1043 if x.before != magic64 || x.after != magic64 { 1044 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1045 } 1046 } 1047 1048 func TestLoadUint64Method(t *testing.T) { 1049 var x struct { 1050 before uint64 1051 i Uint64 1052 after uint64 1053 } 1054 magic64 := uint64(magic64) 1055 x.before = magic64 1056 x.after = magic64 1057 want := uint64(0) 1058 for delta := uint64(1); delta+delta > delta; delta += delta { 1059 k := x.i.Load() 1060 if k != want { 1061 t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) 1062 } 1063 x.i.Store(k + delta) 1064 want = k + delta 1065 } 1066 if x.before != magic64 || x.after != magic64 { 1067 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1068 } 1069 } 1070 1071 func TestLoadUintptr(t *testing.T) { 1072 var x struct { 1073 before uintptr 1074 i uintptr 1075 after uintptr 1076 } 1077 var m uint64 = magic64 1078 magicptr := uintptr(m) 1079 x.before = magicptr 1080 x.after = magicptr 1081 for delta := uintptr(1); delta+delta > delta; delta += delta { 1082 k := LoadUintptr(&x.i) 1083 if k != x.i { 1084 t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) 1085 } 1086 x.i += delta 1087 } 1088 if x.before != magicptr || x.after != magicptr { 1089 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1090 } 1091 } 1092 1093 func TestLoadUintptrMethod(t *testing.T) { 1094 var x struct { 1095 before uintptr 1096 i Uintptr 1097 after uintptr 1098 } 1099 var m uint64 = magic64 1100 magicptr := uintptr(m) 1101 x.before = magicptr 1102 x.after = magicptr 1103 want := uintptr(0) 1104 for delta := uintptr(1); delta+delta > delta; delta += delta { 1105 k := x.i.Load() 1106 if k != want { 1107 t.Fatalf("delta=%d i=%d k=%d want=%d", delta, x.i.Load(), k, want) 1108 } 1109 x.i.Store(k + delta) 1110 want = k + delta 1111 } 1112 if x.before != magicptr || x.after != magicptr { 1113 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1114 } 1115 } 1116 1117 func TestLoadPointer(t *testing.T) { 1118 var x struct { 1119 before uintptr 1120 i unsafe.Pointer 1121 after uintptr 1122 } 1123 var m uint64 = magic64 1124 magicptr := uintptr(m) 1125 x.before = magicptr 1126 x.after = magicptr 1127 for _, p := range testPointers() { 1128 x.i = p 1129 k := LoadPointer(&x.i) 1130 if k != p { 1131 t.Fatalf("p=%x k=%x", p, k) 1132 } 1133 } 1134 if x.before != magicptr || x.after != magicptr { 1135 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1136 } 1137 } 1138 1139 func TestLoadPointerMethod(t *testing.T) { 1140 var x struct { 1141 before uintptr 1142 i Pointer[byte] 1143 after uintptr 1144 } 1145 var m uint64 = magic64 1146 magicptr := uintptr(m) 1147 x.before = magicptr 1148 x.after = magicptr 1149 for _, p := range testPointers() { 1150 p := (*byte)(p) 1151 x.i.Store(p) 1152 k := x.i.Load() 1153 if k != p { 1154 t.Fatalf("p=%x k=%x", p, k) 1155 } 1156 } 1157 if x.before != magicptr || x.after != magicptr { 1158 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1159 } 1160 } 1161 1162 func TestStoreInt32(t *testing.T) { 1163 var x struct { 1164 before int32 1165 i int32 1166 after int32 1167 } 1168 x.before = magic32 1169 x.after = magic32 1170 v := int32(0) 1171 for delta := int32(1); delta+delta > delta; delta += delta { 1172 StoreInt32(&x.i, v) 1173 if x.i != v { 1174 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 1175 } 1176 v += delta 1177 } 1178 if x.before != magic32 || x.after != magic32 { 1179 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 1180 } 1181 } 1182 1183 func TestStoreInt32Method(t *testing.T) { 1184 var x struct { 1185 before int32 1186 i Int32 1187 after int32 1188 } 1189 x.before = magic32 1190 x.after = magic32 1191 v := int32(0) 1192 for delta := int32(1); delta+delta > delta; delta += delta { 1193 x.i.Store(v) 1194 if x.i.Load() != v { 1195 t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) 1196 } 1197 v += delta 1198 } 1199 if x.before != magic32 || x.after != magic32 { 1200 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 1201 } 1202 } 1203 1204 func TestStoreUint32(t *testing.T) { 1205 var x struct { 1206 before uint32 1207 i uint32 1208 after uint32 1209 } 1210 x.before = magic32 1211 x.after = magic32 1212 v := uint32(0) 1213 for delta := uint32(1); delta+delta > delta; delta += delta { 1214 StoreUint32(&x.i, v) 1215 if x.i != v { 1216 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 1217 } 1218 v += delta 1219 } 1220 if x.before != magic32 || x.after != magic32 { 1221 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 1222 } 1223 } 1224 1225 func TestStoreUint32Method(t *testing.T) { 1226 var x struct { 1227 before uint32 1228 i Uint32 1229 after uint32 1230 } 1231 x.before = magic32 1232 x.after = magic32 1233 v := uint32(0) 1234 for delta := uint32(1); delta+delta > delta; delta += delta { 1235 x.i.Store(v) 1236 if x.i.Load() != v { 1237 t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) 1238 } 1239 v += delta 1240 } 1241 if x.before != magic32 || x.after != magic32 { 1242 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) 1243 } 1244 } 1245 1246 func TestStoreInt64(t *testing.T) { 1247 var x struct { 1248 before int64 1249 i int64 1250 after int64 1251 } 1252 magic64 := int64(magic64) 1253 x.before = magic64 1254 x.after = magic64 1255 v := int64(0) 1256 for delta := int64(1); delta+delta > delta; delta += delta { 1257 StoreInt64(&x.i, v) 1258 if x.i != v { 1259 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 1260 } 1261 v += delta 1262 } 1263 if x.before != magic64 || x.after != magic64 { 1264 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1265 } 1266 } 1267 1268 func TestStoreInt64Method(t *testing.T) { 1269 var x struct { 1270 before int64 1271 i Int64 1272 after int64 1273 } 1274 magic64 := int64(magic64) 1275 x.before = magic64 1276 x.after = magic64 1277 v := int64(0) 1278 for delta := int64(1); delta+delta > delta; delta += delta { 1279 x.i.Store(v) 1280 if x.i.Load() != v { 1281 t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) 1282 } 1283 v += delta 1284 } 1285 if x.before != magic64 || x.after != magic64 { 1286 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1287 } 1288 } 1289 1290 func TestStoreUint64(t *testing.T) { 1291 var x struct { 1292 before uint64 1293 i uint64 1294 after uint64 1295 } 1296 magic64 := uint64(magic64) 1297 x.before = magic64 1298 x.after = magic64 1299 v := uint64(0) 1300 for delta := uint64(1); delta+delta > delta; delta += delta { 1301 StoreUint64(&x.i, v) 1302 if x.i != v { 1303 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 1304 } 1305 v += delta 1306 } 1307 if x.before != magic64 || x.after != magic64 { 1308 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1309 } 1310 } 1311 1312 func TestStoreUint64Method(t *testing.T) { 1313 var x struct { 1314 before uint64 1315 i Uint64 1316 after uint64 1317 } 1318 magic64 := uint64(magic64) 1319 x.before = magic64 1320 x.after = magic64 1321 v := uint64(0) 1322 for delta := uint64(1); delta+delta > delta; delta += delta { 1323 x.i.Store(v) 1324 if x.i.Load() != v { 1325 t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) 1326 } 1327 v += delta 1328 } 1329 if x.before != magic64 || x.after != magic64 { 1330 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64) 1331 } 1332 } 1333 1334 func TestStoreUintptr(t *testing.T) { 1335 var x struct { 1336 before uintptr 1337 i uintptr 1338 after uintptr 1339 } 1340 var m uint64 = magic64 1341 magicptr := uintptr(m) 1342 x.before = magicptr 1343 x.after = magicptr 1344 v := uintptr(0) 1345 for delta := uintptr(1); delta+delta > delta; delta += delta { 1346 StoreUintptr(&x.i, v) 1347 if x.i != v { 1348 t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) 1349 } 1350 v += delta 1351 } 1352 if x.before != magicptr || x.after != magicptr { 1353 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1354 } 1355 } 1356 1357 func TestStoreUintptrMethod(t *testing.T) { 1358 var x struct { 1359 before uintptr 1360 i Uintptr 1361 after uintptr 1362 } 1363 var m uint64 = magic64 1364 magicptr := uintptr(m) 1365 x.before = magicptr 1366 x.after = magicptr 1367 v := uintptr(0) 1368 for delta := uintptr(1); delta+delta > delta; delta += delta { 1369 x.i.Store(v) 1370 if x.i.Load() != v { 1371 t.Fatalf("delta=%d i=%d v=%d", delta, x.i.Load(), v) 1372 } 1373 v += delta 1374 } 1375 if x.before != magicptr || x.after != magicptr { 1376 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1377 } 1378 } 1379 1380 func TestStorePointer(t *testing.T) { 1381 var x struct { 1382 before uintptr 1383 i unsafe.Pointer 1384 after uintptr 1385 } 1386 var m uint64 = magic64 1387 magicptr := uintptr(m) 1388 x.before = magicptr 1389 x.after = magicptr 1390 for _, p := range testPointers() { 1391 StorePointer(&x.i, p) 1392 if x.i != p { 1393 t.Fatalf("x.i=%p p=%p", x.i, p) 1394 } 1395 } 1396 if x.before != magicptr || x.after != magicptr { 1397 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1398 } 1399 } 1400 1401 func TestStorePointerMethod(t *testing.T) { 1402 var x struct { 1403 before uintptr 1404 i Pointer[byte] 1405 after uintptr 1406 } 1407 var m uint64 = magic64 1408 magicptr := uintptr(m) 1409 x.before = magicptr 1410 x.after = magicptr 1411 for _, p := range testPointers() { 1412 p := (*byte)(p) 1413 x.i.Store(p) 1414 if x.i.Load() != p { 1415 t.Fatalf("x.i=%p p=%p", x.i.Load(), p) 1416 } 1417 } 1418 if x.before != magicptr || x.after != magicptr { 1419 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr) 1420 } 1421 } 1422 1423 // Tests of correct behavior, with contention. 1424 // (Is the function atomic?) 1425 // 1426 // For each function, we write a "hammer" function that repeatedly 1427 // uses the atomic operation to add 1 to a value. After running 1428 // multiple hammers in parallel, check that we end with the correct 1429 // total. 1430 // Swap can't add 1, so it uses a different scheme. 1431 // The functions repeatedly generate a pseudo-random number such that 1432 // low bits are equal to high bits, swap, check that the old value 1433 // has low and high bits equal. 1434 1435 var hammer32 = map[string]func(*uint32, int){ 1436 "SwapInt32": hammerSwapInt32, 1437 "SwapUint32": hammerSwapUint32, 1438 "SwapUintptr": hammerSwapUintptr32, 1439 "AddInt32": hammerAddInt32, 1440 "AddUint32": hammerAddUint32, 1441 "AddUintptr": hammerAddUintptr32, 1442 "CompareAndSwapInt32": hammerCompareAndSwapInt32, 1443 "CompareAndSwapUint32": hammerCompareAndSwapUint32, 1444 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr32, 1445 1446 "SwapInt32Method": hammerSwapInt32Method, 1447 "SwapUint32Method": hammerSwapUint32Method, 1448 "SwapUintptrMethod": hammerSwapUintptr32Method, 1449 "AddInt32Method": hammerAddInt32Method, 1450 "AddUint32Method": hammerAddUint32Method, 1451 "AddUintptrMethod": hammerAddUintptr32Method, 1452 "CompareAndSwapInt32Method": hammerCompareAndSwapInt32Method, 1453 "CompareAndSwapUint32Method": hammerCompareAndSwapUint32Method, 1454 "CompareAndSwapUintptrMethod": hammerCompareAndSwapUintptr32Method, 1455 } 1456 1457 func init() { 1458 var v uint64 = 1 << 50 1459 if uintptr(v) != 0 { 1460 // 64-bit system; clear uintptr tests 1461 delete(hammer32, "SwapUintptr") 1462 delete(hammer32, "AddUintptr") 1463 delete(hammer32, "CompareAndSwapUintptr") 1464 delete(hammer32, "SwapUintptrMethod") 1465 delete(hammer32, "AddUintptrMethod") 1466 delete(hammer32, "CompareAndSwapUintptrMethod") 1467 } 1468 } 1469 1470 func hammerSwapInt32(uaddr *uint32, count int) { 1471 addr := (*int32)(unsafe.Pointer(uaddr)) 1472 seed := int(uintptr(unsafe.Pointer(&count))) 1473 for i := 0; i < count; i++ { 1474 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 1475 old := uint32(SwapInt32(addr, int32(new))) 1476 if old>>16 != old<<16>>16 { 1477 panic(fmt.Sprintf("SwapInt32 is not atomic: %v", old)) 1478 } 1479 } 1480 } 1481 1482 func hammerSwapInt32Method(uaddr *uint32, count int) { 1483 addr := (*Int32)(unsafe.Pointer(uaddr)) 1484 seed := int(uintptr(unsafe.Pointer(&count))) 1485 for i := 0; i < count; i++ { 1486 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 1487 old := uint32(addr.Swap(int32(new))) 1488 if old>>16 != old<<16>>16 { 1489 panic(fmt.Sprintf("SwapInt32 is not atomic: %v", old)) 1490 } 1491 } 1492 } 1493 1494 func hammerSwapUint32(addr *uint32, count int) { 1495 seed := int(uintptr(unsafe.Pointer(&count))) 1496 for i := 0; i < count; i++ { 1497 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 1498 old := SwapUint32(addr, new) 1499 if old>>16 != old<<16>>16 { 1500 panic(fmt.Sprintf("SwapUint32 is not atomic: %v", old)) 1501 } 1502 } 1503 } 1504 1505 func hammerSwapUint32Method(uaddr *uint32, count int) { 1506 addr := (*Uint32)(unsafe.Pointer(uaddr)) 1507 seed := int(uintptr(unsafe.Pointer(&count))) 1508 for i := 0; i < count; i++ { 1509 new := uint32(seed+i)<<16 | uint32(seed+i)<<16>>16 1510 old := addr.Swap(new) 1511 if old>>16 != old<<16>>16 { 1512 panic(fmt.Sprintf("SwapUint32 is not atomic: %v", old)) 1513 } 1514 } 1515 } 1516 1517 func hammerSwapUintptr32(uaddr *uint32, count int) { 1518 // only safe when uintptr is 32-bit. 1519 // not called on 64-bit systems. 1520 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1521 seed := int(uintptr(unsafe.Pointer(&count))) 1522 for i := 0; i < count; i++ { 1523 new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 1524 old := SwapUintptr(addr, new) 1525 if old>>16 != old<<16>>16 { 1526 panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old)) 1527 } 1528 } 1529 } 1530 1531 func hammerSwapUintptr32Method(uaddr *uint32, count int) { 1532 // only safe when uintptr is 32-bit. 1533 // not called on 64-bit systems. 1534 addr := (*Uintptr)(unsafe.Pointer(uaddr)) 1535 seed := int(uintptr(unsafe.Pointer(&count))) 1536 for i := 0; i < count; i++ { 1537 new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 1538 old := addr.Swap(new) 1539 if old>>16 != old<<16>>16 { 1540 panic(fmt.Sprintf("Uintptr.Swap is not atomic: %#08x", old)) 1541 } 1542 } 1543 } 1544 1545 func hammerAddInt32(uaddr *uint32, count int) { 1546 addr := (*int32)(unsafe.Pointer(uaddr)) 1547 for i := 0; i < count; i++ { 1548 AddInt32(addr, 1) 1549 } 1550 } 1551 1552 func hammerAddInt32Method(uaddr *uint32, count int) { 1553 addr := (*Int32)(unsafe.Pointer(uaddr)) 1554 for i := 0; i < count; i++ { 1555 addr.Add(1) 1556 } 1557 } 1558 1559 func hammerAddUint32(addr *uint32, count int) { 1560 for i := 0; i < count; i++ { 1561 AddUint32(addr, 1) 1562 } 1563 } 1564 1565 func hammerAddUint32Method(uaddr *uint32, count int) { 1566 addr := (*Uint32)(unsafe.Pointer(uaddr)) 1567 for i := 0; i < count; i++ { 1568 addr.Add(1) 1569 } 1570 } 1571 1572 func hammerAddUintptr32(uaddr *uint32, count int) { 1573 // only safe when uintptr is 32-bit. 1574 // not called on 64-bit systems. 1575 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1576 for i := 0; i < count; i++ { 1577 AddUintptr(addr, 1) 1578 } 1579 } 1580 1581 func hammerAddUintptr32Method(uaddr *uint32, count int) { 1582 // only safe when uintptr is 32-bit. 1583 // not called on 64-bit systems. 1584 addr := (*Uintptr)(unsafe.Pointer(uaddr)) 1585 for i := 0; i < count; i++ { 1586 addr.Add(1) 1587 } 1588 } 1589 1590 func hammerCompareAndSwapInt32(uaddr *uint32, count int) { 1591 addr := (*int32)(unsafe.Pointer(uaddr)) 1592 for i := 0; i < count; i++ { 1593 for { 1594 v := LoadInt32(addr) 1595 if CompareAndSwapInt32(addr, v, v+1) { 1596 break 1597 } 1598 } 1599 } 1600 } 1601 1602 func hammerCompareAndSwapInt32Method(uaddr *uint32, count int) { 1603 addr := (*Int32)(unsafe.Pointer(uaddr)) 1604 for i := 0; i < count; i++ { 1605 for { 1606 v := addr.Load() 1607 if addr.CompareAndSwap(v, v+1) { 1608 break 1609 } 1610 } 1611 } 1612 } 1613 1614 func hammerCompareAndSwapUint32(addr *uint32, count int) { 1615 for i := 0; i < count; i++ { 1616 for { 1617 v := LoadUint32(addr) 1618 if CompareAndSwapUint32(addr, v, v+1) { 1619 break 1620 } 1621 } 1622 } 1623 } 1624 1625 func hammerCompareAndSwapUint32Method(uaddr *uint32, count int) { 1626 addr := (*Uint32)(unsafe.Pointer(uaddr)) 1627 for i := 0; i < count; i++ { 1628 for { 1629 v := addr.Load() 1630 if addr.CompareAndSwap(v, v+1) { 1631 break 1632 } 1633 } 1634 } 1635 } 1636 1637 func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) { 1638 // only safe when uintptr is 32-bit. 1639 // not called on 64-bit systems. 1640 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1641 for i := 0; i < count; i++ { 1642 for { 1643 v := LoadUintptr(addr) 1644 if CompareAndSwapUintptr(addr, v, v+1) { 1645 break 1646 } 1647 } 1648 } 1649 } 1650 1651 func hammerCompareAndSwapUintptr32Method(uaddr *uint32, count int) { 1652 // only safe when uintptr is 32-bit. 1653 // not called on 64-bit systems. 1654 addr := (*Uintptr)(unsafe.Pointer(uaddr)) 1655 for i := 0; i < count; i++ { 1656 for { 1657 v := addr.Load() 1658 if addr.CompareAndSwap(v, v+1) { 1659 break 1660 } 1661 } 1662 } 1663 } 1664 1665 func TestHammer32(t *testing.T) { 1666 const p = 4 1667 n := 100000 1668 if testing.Short() { 1669 n = 1000 1670 } 1671 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 1672 1673 for name, testf := range hammer32 { 1674 c := make(chan int) 1675 var val uint32 1676 for i := 0; i < p; i++ { 1677 go func() { 1678 defer func() { 1679 if err := recover(); err != nil { 1680 t.Error(err.(string)) 1681 } 1682 c <- 1 1683 }() 1684 testf(&val, n) 1685 }() 1686 } 1687 for i := 0; i < p; i++ { 1688 <-c 1689 } 1690 if !strings.HasPrefix(name, "Swap") && val != uint32(n)*p { 1691 t.Fatalf("%s: val=%d want %d", name, val, n*p) 1692 } 1693 } 1694 } 1695 1696 var hammer64 = map[string]func(*uint64, int){ 1697 "SwapInt64": hammerSwapInt64, 1698 "SwapUint64": hammerSwapUint64, 1699 "SwapUintptr": hammerSwapUintptr64, 1700 "AddInt64": hammerAddInt64, 1701 "AddUint64": hammerAddUint64, 1702 "AddUintptr": hammerAddUintptr64, 1703 "CompareAndSwapInt64": hammerCompareAndSwapInt64, 1704 "CompareAndSwapUint64": hammerCompareAndSwapUint64, 1705 "CompareAndSwapUintptr": hammerCompareAndSwapUintptr64, 1706 1707 "SwapInt64Method": hammerSwapInt64Method, 1708 "SwapUint64Method": hammerSwapUint64Method, 1709 "SwapUintptrMethod": hammerSwapUintptr64Method, 1710 "AddInt64Method": hammerAddInt64Method, 1711 "AddUint64Method": hammerAddUint64Method, 1712 "AddUintptrMethod": hammerAddUintptr64Method, 1713 "CompareAndSwapInt64Method": hammerCompareAndSwapInt64Method, 1714 "CompareAndSwapUint64Method": hammerCompareAndSwapUint64Method, 1715 "CompareAndSwapUintptrMethod": hammerCompareAndSwapUintptr64Method, 1716 } 1717 1718 func init() { 1719 var v uint64 = 1 << 50 1720 if uintptr(v) == 0 { 1721 // 32-bit system; clear uintptr tests 1722 delete(hammer64, "SwapUintptr") 1723 delete(hammer64, "SwapUintptrMethod") 1724 delete(hammer64, "AddUintptr") 1725 delete(hammer64, "AddUintptrMethod") 1726 delete(hammer64, "CompareAndSwapUintptr") 1727 delete(hammer64, "CompareAndSwapUintptrMethod") 1728 } 1729 } 1730 1731 func hammerSwapInt64(uaddr *uint64, count int) { 1732 addr := (*int64)(unsafe.Pointer(uaddr)) 1733 seed := int(uintptr(unsafe.Pointer(&count))) 1734 for i := 0; i < count; i++ { 1735 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 1736 old := uint64(SwapInt64(addr, int64(new))) 1737 if old>>32 != old<<32>>32 { 1738 panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) 1739 } 1740 } 1741 } 1742 1743 func hammerSwapInt64Method(uaddr *uint64, count int) { 1744 addr := (*Int64)(unsafe.Pointer(uaddr)) 1745 seed := int(uintptr(unsafe.Pointer(&count))) 1746 for i := 0; i < count; i++ { 1747 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 1748 old := uint64(addr.Swap(int64(new))) 1749 if old>>32 != old<<32>>32 { 1750 panic(fmt.Sprintf("SwapInt64 is not atomic: %v", old)) 1751 } 1752 } 1753 } 1754 1755 func hammerSwapUint64(addr *uint64, count int) { 1756 seed := int(uintptr(unsafe.Pointer(&count))) 1757 for i := 0; i < count; i++ { 1758 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 1759 old := SwapUint64(addr, new) 1760 if old>>32 != old<<32>>32 { 1761 panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) 1762 } 1763 } 1764 } 1765 1766 func hammerSwapUint64Method(uaddr *uint64, count int) { 1767 addr := (*Uint64)(unsafe.Pointer(uaddr)) 1768 seed := int(uintptr(unsafe.Pointer(&count))) 1769 for i := 0; i < count; i++ { 1770 new := uint64(seed+i)<<32 | uint64(seed+i)<<32>>32 1771 old := addr.Swap(new) 1772 if old>>32 != old<<32>>32 { 1773 panic(fmt.Sprintf("SwapUint64 is not atomic: %v", old)) 1774 } 1775 } 1776 } 1777 1778 const arch32 = unsafe.Sizeof(uintptr(0)) == 4 1779 1780 func hammerSwapUintptr64(uaddr *uint64, count int) { 1781 // only safe when uintptr is 64-bit. 1782 // not called on 32-bit systems. 1783 if !arch32 { 1784 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1785 seed := int(uintptr(unsafe.Pointer(&count))) 1786 for i := 0; i < count; i++ { 1787 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 1788 old := SwapUintptr(addr, new) 1789 if old>>32 != old<<32>>32 { 1790 panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) 1791 } 1792 } 1793 } 1794 } 1795 1796 func hammerSwapUintptr64Method(uaddr *uint64, count int) { 1797 // only safe when uintptr is 64-bit. 1798 // not called on 32-bit systems. 1799 if !arch32 { 1800 addr := (*Uintptr)(unsafe.Pointer(uaddr)) 1801 seed := int(uintptr(unsafe.Pointer(&count))) 1802 for i := 0; i < count; i++ { 1803 new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 1804 old := addr.Swap(new) 1805 if old>>32 != old<<32>>32 { 1806 panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) 1807 } 1808 } 1809 } 1810 } 1811 1812 func hammerAddInt64(uaddr *uint64, count int) { 1813 addr := (*int64)(unsafe.Pointer(uaddr)) 1814 for i := 0; i < count; i++ { 1815 AddInt64(addr, 1) 1816 } 1817 } 1818 1819 func hammerAddInt64Method(uaddr *uint64, count int) { 1820 addr := (*Int64)(unsafe.Pointer(uaddr)) 1821 for i := 0; i < count; i++ { 1822 addr.Add(1) 1823 } 1824 } 1825 1826 func hammerAddUint64(addr *uint64, count int) { 1827 for i := 0; i < count; i++ { 1828 AddUint64(addr, 1) 1829 } 1830 } 1831 1832 func hammerAddUint64Method(uaddr *uint64, count int) { 1833 addr := (*Uint64)(unsafe.Pointer(uaddr)) 1834 for i := 0; i < count; i++ { 1835 addr.Add(1) 1836 } 1837 } 1838 1839 func hammerAddUintptr64(uaddr *uint64, count int) { 1840 // only safe when uintptr is 64-bit. 1841 // not called on 32-bit systems. 1842 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1843 for i := 0; i < count; i++ { 1844 AddUintptr(addr, 1) 1845 } 1846 } 1847 1848 func hammerAddUintptr64Method(uaddr *uint64, count int) { 1849 // only safe when uintptr is 64-bit. 1850 // not called on 32-bit systems. 1851 addr := (*Uintptr)(unsafe.Pointer(uaddr)) 1852 for i := 0; i < count; i++ { 1853 addr.Add(1) 1854 } 1855 } 1856 1857 func hammerCompareAndSwapInt64(uaddr *uint64, count int) { 1858 addr := (*int64)(unsafe.Pointer(uaddr)) 1859 for i := 0; i < count; i++ { 1860 for { 1861 v := LoadInt64(addr) 1862 if CompareAndSwapInt64(addr, v, v+1) { 1863 break 1864 } 1865 } 1866 } 1867 } 1868 1869 func hammerCompareAndSwapInt64Method(uaddr *uint64, count int) { 1870 addr := (*Int64)(unsafe.Pointer(uaddr)) 1871 for i := 0; i < count; i++ { 1872 for { 1873 v := addr.Load() 1874 if addr.CompareAndSwap(v, v+1) { 1875 break 1876 } 1877 } 1878 } 1879 } 1880 1881 func hammerCompareAndSwapUint64(addr *uint64, count int) { 1882 for i := 0; i < count; i++ { 1883 for { 1884 v := LoadUint64(addr) 1885 if CompareAndSwapUint64(addr, v, v+1) { 1886 break 1887 } 1888 } 1889 } 1890 } 1891 1892 func hammerCompareAndSwapUint64Method(uaddr *uint64, count int) { 1893 addr := (*Uint64)(unsafe.Pointer(uaddr)) 1894 for i := 0; i < count; i++ { 1895 for { 1896 v := addr.Load() 1897 if addr.CompareAndSwap(v, v+1) { 1898 break 1899 } 1900 } 1901 } 1902 } 1903 1904 func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) { 1905 // only safe when uintptr is 64-bit. 1906 // not called on 32-bit systems. 1907 addr := (*uintptr)(unsafe.Pointer(uaddr)) 1908 for i := 0; i < count; i++ { 1909 for { 1910 v := LoadUintptr(addr) 1911 if CompareAndSwapUintptr(addr, v, v+1) { 1912 break 1913 } 1914 } 1915 } 1916 } 1917 1918 func hammerCompareAndSwapUintptr64Method(uaddr *uint64, count int) { 1919 // only safe when uintptr is 64-bit. 1920 // not called on 32-bit systems. 1921 addr := (*Uintptr)(unsafe.Pointer(uaddr)) 1922 for i := 0; i < count; i++ { 1923 for { 1924 v := addr.Load() 1925 if addr.CompareAndSwap(v, v+1) { 1926 break 1927 } 1928 } 1929 } 1930 } 1931 1932 func TestHammer64(t *testing.T) { 1933 const p = 4 1934 n := 100000 1935 if testing.Short() { 1936 n = 1000 1937 } 1938 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p)) 1939 1940 for name, testf := range hammer64 { 1941 c := make(chan int) 1942 var val uint64 1943 for i := 0; i < p; i++ { 1944 go func() { 1945 defer func() { 1946 if err := recover(); err != nil { 1947 t.Error(err.(string)) 1948 } 1949 c <- 1 1950 }() 1951 testf(&val, n) 1952 }() 1953 } 1954 for i := 0; i < p; i++ { 1955 <-c 1956 } 1957 if !strings.HasPrefix(name, "Swap") && val != uint64(n)*p { 1958 t.Fatalf("%s: val=%d want %d", name, val, n*p) 1959 } 1960 } 1961 } 1962 1963 func hammerStoreLoadInt32(t *testing.T, paddr unsafe.Pointer) { 1964 addr := (*int32)(paddr) 1965 v := LoadInt32(addr) 1966 vlo := v & ((1 << 16) - 1) 1967 vhi := v >> 16 1968 if vlo != vhi { 1969 t.Fatalf("Int32: %#x != %#x", vlo, vhi) 1970 } 1971 new := v + 1 + 1<<16 1972 if vlo == 1e4 { 1973 new = 0 1974 } 1975 StoreInt32(addr, new) 1976 } 1977 1978 func hammerStoreLoadInt32Method(t *testing.T, paddr unsafe.Pointer) { 1979 addr := (*int32)(paddr) 1980 v := LoadInt32(addr) 1981 vlo := v & ((1 << 16) - 1) 1982 vhi := v >> 16 1983 if vlo != vhi { 1984 t.Fatalf("Int32: %#x != %#x", vlo, vhi) 1985 } 1986 new := v + 1 + 1<<16 1987 if vlo == 1e4 { 1988 new = 0 1989 } 1990 StoreInt32(addr, new) 1991 } 1992 1993 func hammerStoreLoadUint32(t *testing.T, paddr unsafe.Pointer) { 1994 addr := (*uint32)(paddr) 1995 v := LoadUint32(addr) 1996 vlo := v & ((1 << 16) - 1) 1997 vhi := v >> 16 1998 if vlo != vhi { 1999 t.Fatalf("Uint32: %#x != %#x", vlo, vhi) 2000 } 2001 new := v + 1 + 1<<16 2002 if vlo == 1e4 { 2003 new = 0 2004 } 2005 StoreUint32(addr, new) 2006 } 2007 2008 func hammerStoreLoadUint32Method(t *testing.T, paddr unsafe.Pointer) { 2009 addr := (*Uint32)(paddr) 2010 v := addr.Load() 2011 vlo := v & ((1 << 16) - 1) 2012 vhi := v >> 16 2013 if vlo != vhi { 2014 t.Fatalf("Uint32: %#x != %#x", vlo, vhi) 2015 } 2016 new := v + 1 + 1<<16 2017 if vlo == 1e4 { 2018 new = 0 2019 } 2020 addr.Store(new) 2021 } 2022 2023 func hammerStoreLoadInt64(t *testing.T, paddr unsafe.Pointer) { 2024 addr := (*int64)(paddr) 2025 v := LoadInt64(addr) 2026 vlo := v & ((1 << 32) - 1) 2027 vhi := v >> 32 2028 if vlo != vhi { 2029 t.Fatalf("Int64: %#x != %#x", vlo, vhi) 2030 } 2031 new := v + 1 + 1<<32 2032 StoreInt64(addr, new) 2033 } 2034 2035 func hammerStoreLoadInt64Method(t *testing.T, paddr unsafe.Pointer) { 2036 addr := (*Int64)(paddr) 2037 v := addr.Load() 2038 vlo := v & ((1 << 32) - 1) 2039 vhi := v >> 32 2040 if vlo != vhi { 2041 t.Fatalf("Int64: %#x != %#x", vlo, vhi) 2042 } 2043 new := v + 1 + 1<<32 2044 addr.Store(new) 2045 } 2046 2047 func hammerStoreLoadUint64(t *testing.T, paddr unsafe.Pointer) { 2048 addr := (*uint64)(paddr) 2049 v := LoadUint64(addr) 2050 vlo := v & ((1 << 32) - 1) 2051 vhi := v >> 32 2052 if vlo != vhi { 2053 t.Fatalf("Uint64: %#x != %#x", vlo, vhi) 2054 } 2055 new := v + 1 + 1<<32 2056 StoreUint64(addr, new) 2057 } 2058 2059 func hammerStoreLoadUint64Method(t *testing.T, paddr unsafe.Pointer) { 2060 addr := (*Uint64)(paddr) 2061 v := addr.Load() 2062 vlo := v & ((1 << 32) - 1) 2063 vhi := v >> 32 2064 if vlo != vhi { 2065 t.Fatalf("Uint64: %#x != %#x", vlo, vhi) 2066 } 2067 new := v + 1 + 1<<32 2068 addr.Store(new) 2069 } 2070 2071 func hammerStoreLoadUintptr(t *testing.T, paddr unsafe.Pointer) { 2072 addr := (*uintptr)(paddr) 2073 v := LoadUintptr(addr) 2074 new := v 2075 if arch32 { 2076 vlo := v & ((1 << 16) - 1) 2077 vhi := v >> 16 2078 if vlo != vhi { 2079 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 2080 } 2081 new = v + 1 + 1<<16 2082 if vlo == 1e4 { 2083 new = 0 2084 } 2085 } else { 2086 vlo := v & ((1 << 32) - 1) 2087 vhi := v >> 32 2088 if vlo != vhi { 2089 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 2090 } 2091 inc := uint64(1 + 1<<32) 2092 new = v + uintptr(inc) 2093 } 2094 StoreUintptr(addr, new) 2095 } 2096 2097 //go:nocheckptr 2098 func hammerStoreLoadUintptrMethod(t *testing.T, paddr unsafe.Pointer) { 2099 addr := (*Uintptr)(paddr) 2100 v := addr.Load() 2101 new := v 2102 if arch32 { 2103 vlo := v & ((1 << 16) - 1) 2104 vhi := v >> 16 2105 if vlo != vhi { 2106 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 2107 } 2108 new = v + 1 + 1<<16 2109 if vlo == 1e4 { 2110 new = 0 2111 } 2112 } else { 2113 vlo := v & ((1 << 32) - 1) 2114 vhi := v >> 32 2115 if vlo != vhi { 2116 t.Fatalf("Uintptr: %#x != %#x", vlo, vhi) 2117 } 2118 inc := uint64(1 + 1<<32) 2119 new = v + uintptr(inc) 2120 } 2121 addr.Store(new) 2122 } 2123 2124 // This code is just testing that LoadPointer/StorePointer operate 2125 // atomically; it's not actually calculating pointers. 2126 // 2127 //go:nocheckptr 2128 func hammerStoreLoadPointer(t *testing.T, paddr unsafe.Pointer) { 2129 addr := (*unsafe.Pointer)(paddr) 2130 v := uintptr(LoadPointer(addr)) 2131 new := v 2132 if arch32 { 2133 vlo := v & ((1 << 16) - 1) 2134 vhi := v >> 16 2135 if vlo != vhi { 2136 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 2137 } 2138 new = v + 1 + 1<<16 2139 if vlo == 1e4 { 2140 new = 0 2141 } 2142 } else { 2143 vlo := v & ((1 << 32) - 1) 2144 vhi := v >> 32 2145 if vlo != vhi { 2146 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 2147 } 2148 inc := uint64(1 + 1<<32) 2149 new = v + uintptr(inc) 2150 } 2151 StorePointer(addr, unsafe.Pointer(new)) 2152 } 2153 2154 // This code is just testing that LoadPointer/StorePointer operate 2155 // atomically; it's not actually calculating pointers. 2156 // 2157 //go:nocheckptr 2158 func hammerStoreLoadPointerMethod(t *testing.T, paddr unsafe.Pointer) { 2159 addr := (*Pointer[byte])(paddr) 2160 v := uintptr(unsafe.Pointer(addr.Load())) 2161 new := v 2162 if arch32 { 2163 vlo := v & ((1 << 16) - 1) 2164 vhi := v >> 16 2165 if vlo != vhi { 2166 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 2167 } 2168 new = v + 1 + 1<<16 2169 if vlo == 1e4 { 2170 new = 0 2171 } 2172 } else { 2173 vlo := v & ((1 << 32) - 1) 2174 vhi := v >> 32 2175 if vlo != vhi { 2176 t.Fatalf("Pointer: %#x != %#x", vlo, vhi) 2177 } 2178 inc := uint64(1 + 1<<32) 2179 new = v + uintptr(inc) 2180 } 2181 addr.Store((*byte)(unsafe.Pointer(new))) 2182 } 2183 2184 func TestHammerStoreLoad(t *testing.T) { 2185 tests := []func(*testing.T, unsafe.Pointer){ 2186 hammerStoreLoadInt32, hammerStoreLoadUint32, 2187 hammerStoreLoadUintptr, hammerStoreLoadPointer, 2188 hammerStoreLoadInt32Method, hammerStoreLoadUint32Method, 2189 hammerStoreLoadUintptrMethod, hammerStoreLoadPointerMethod, 2190 hammerStoreLoadInt64, hammerStoreLoadUint64, 2191 hammerStoreLoadInt64Method, hammerStoreLoadUint64Method, 2192 } 2193 n := int(1e6) 2194 if testing.Short() { 2195 n = int(1e4) 2196 } 2197 const procs = 8 2198 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs)) 2199 // Disable the GC because hammerStoreLoadPointer invokes 2200 // write barriers on values that aren't real pointers. 2201 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 2202 // Ensure any in-progress GC is finished. 2203 runtime.GC() 2204 for _, tt := range tests { 2205 c := make(chan int) 2206 var val uint64 2207 for p := 0; p < procs; p++ { 2208 go func() { 2209 for i := 0; i < n; i++ { 2210 tt(t, unsafe.Pointer(&val)) 2211 } 2212 c <- 1 2213 }() 2214 } 2215 for p := 0; p < procs; p++ { 2216 <-c 2217 } 2218 } 2219 } 2220 2221 func TestStoreLoadSeqCst32(t *testing.T) { 2222 if runtime.NumCPU() == 1 { 2223 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 2224 } 2225 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 2226 N := int32(1e3) 2227 if testing.Short() { 2228 N = int32(1e2) 2229 } 2230 c := make(chan bool, 2) 2231 X := [2]int32{} 2232 ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}} 2233 for p := 0; p < 2; p++ { 2234 go func(me int) { 2235 he := 1 - me 2236 for i := int32(1); i < N; i++ { 2237 StoreInt32(&X[me], i) 2238 my := LoadInt32(&X[he]) 2239 StoreInt32(&ack[me][i%3], my) 2240 for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ { 2241 if w%1000 == 0 { 2242 runtime.Gosched() 2243 } 2244 } 2245 his := LoadInt32(&ack[he][i%3]) 2246 if (my != i && my != i-1) || (his != i && his != i-1) { 2247 t.Errorf("invalid values: %d/%d (%d)", my, his, i) 2248 break 2249 } 2250 if my != i && his != i { 2251 t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 2252 break 2253 } 2254 StoreInt32(&ack[me][(i-1)%3], -1) 2255 } 2256 c <- true 2257 }(p) 2258 } 2259 <-c 2260 <-c 2261 } 2262 2263 func TestStoreLoadSeqCst64(t *testing.T) { 2264 if runtime.NumCPU() == 1 { 2265 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 2266 } 2267 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 2268 N := int64(1e3) 2269 if testing.Short() { 2270 N = int64(1e2) 2271 } 2272 c := make(chan bool, 2) 2273 X := [2]int64{} 2274 ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}} 2275 for p := 0; p < 2; p++ { 2276 go func(me int) { 2277 he := 1 - me 2278 for i := int64(1); i < N; i++ { 2279 StoreInt64(&X[me], i) 2280 my := LoadInt64(&X[he]) 2281 StoreInt64(&ack[me][i%3], my) 2282 for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ { 2283 if w%1000 == 0 { 2284 runtime.Gosched() 2285 } 2286 } 2287 his := LoadInt64(&ack[he][i%3]) 2288 if (my != i && my != i-1) || (his != i && his != i-1) { 2289 t.Errorf("invalid values: %d/%d (%d)", my, his, i) 2290 break 2291 } 2292 if my != i && his != i { 2293 t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) 2294 break 2295 } 2296 StoreInt64(&ack[me][(i-1)%3], -1) 2297 } 2298 c <- true 2299 }(p) 2300 } 2301 <-c 2302 <-c 2303 } 2304 2305 func TestStoreLoadRelAcq32(t *testing.T) { 2306 if runtime.NumCPU() == 1 { 2307 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 2308 } 2309 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 2310 N := int32(1e3) 2311 if testing.Short() { 2312 N = int32(1e2) 2313 } 2314 c := make(chan bool, 2) 2315 type Data struct { 2316 signal int32 2317 pad1 [128]int8 2318 data1 int32 2319 pad2 [128]int8 2320 data2 float32 2321 } 2322 var X Data 2323 for p := int32(0); p < 2; p++ { 2324 go func(p int32) { 2325 for i := int32(1); i < N; i++ { 2326 if (i+p)%2 == 0 { 2327 X.data1 = i 2328 X.data2 = float32(i) 2329 StoreInt32(&X.signal, i) 2330 } else { 2331 for w := 1; LoadInt32(&X.signal) != i; w++ { 2332 if w%1000 == 0 { 2333 runtime.Gosched() 2334 } 2335 } 2336 d1 := X.data1 2337 d2 := X.data2 2338 if d1 != i || d2 != float32(i) { 2339 t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i) 2340 break 2341 } 2342 } 2343 } 2344 c <- true 2345 }(p) 2346 } 2347 <-c 2348 <-c 2349 } 2350 2351 func TestStoreLoadRelAcq64(t *testing.T) { 2352 if runtime.NumCPU() == 1 { 2353 t.Skipf("Skipping test on %v processor machine", runtime.NumCPU()) 2354 } 2355 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 2356 N := int64(1e3) 2357 if testing.Short() { 2358 N = int64(1e2) 2359 } 2360 c := make(chan bool, 2) 2361 type Data struct { 2362 signal int64 2363 pad1 [128]int8 2364 data1 int64 2365 pad2 [128]int8 2366 data2 float64 2367 } 2368 var X Data 2369 for p := int64(0); p < 2; p++ { 2370 go func(p int64) { 2371 for i := int64(1); i < N; i++ { 2372 if (i+p)%2 == 0 { 2373 X.data1 = i 2374 X.data2 = float64(i) 2375 StoreInt64(&X.signal, i) 2376 } else { 2377 for w := 1; LoadInt64(&X.signal) != i; w++ { 2378 if w%1000 == 0 { 2379 runtime.Gosched() 2380 } 2381 } 2382 d1 := X.data1 2383 d2 := X.data2 2384 if d1 != i || d2 != float64(i) { 2385 t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i) 2386 break 2387 } 2388 } 2389 } 2390 c <- true 2391 }(p) 2392 } 2393 <-c 2394 <-c 2395 } 2396 2397 func shouldPanic(t *testing.T, name string, f func()) { 2398 defer func() { 2399 // Check that all GC maps are sane. 2400 runtime.GC() 2401 2402 err := recover() 2403 want := "unaligned 64-bit atomic operation" 2404 if err == nil { 2405 t.Errorf("%s did not panic", name) 2406 } else if s, _ := err.(string); s != want { 2407 t.Errorf("%s: wanted panic %q, got %q", name, want, err) 2408 } 2409 }() 2410 f() 2411 } 2412 2413 func TestUnaligned64(t *testing.T) { 2414 // Unaligned 64-bit atomics on 32-bit systems are 2415 // a continual source of pain. Test that on 32-bit systems they crash 2416 // instead of failing silently. 2417 if !arch32 { 2418 t.Skip("test only runs on 32-bit systems") 2419 } 2420 2421 x := make([]uint32, 4) 2422 p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned 2423 2424 shouldPanic(t, "LoadUint64", func() { LoadUint64(p) }) 2425 shouldPanic(t, "LoadUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).Load() }) 2426 shouldPanic(t, "StoreUint64", func() { StoreUint64(p, 1) }) 2427 shouldPanic(t, "StoreUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).Store(1) }) 2428 shouldPanic(t, "CompareAndSwapUint64", func() { CompareAndSwapUint64(p, 1, 2) }) 2429 shouldPanic(t, "CompareAndSwapUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).CompareAndSwap(1, 2) }) 2430 shouldPanic(t, "AddUint64", func() { AddUint64(p, 3) }) 2431 shouldPanic(t, "AddUint64Method", func() { (*Uint64)(unsafe.Pointer(p)).Add(3) }) 2432 } 2433 2434 func TestAutoAligned64(t *testing.T) { 2435 var signed struct { 2436 _ uint32 2437 i Int64 2438 } 2439 if o := reflect.TypeOf(&signed).Elem().Field(1).Offset; o != 8 { 2440 t.Fatalf("Int64 offset = %d, want 8", o) 2441 } 2442 if p := reflect.ValueOf(&signed).Elem().Field(1).Addr().Pointer(); p&7 != 0 { 2443 t.Fatalf("Int64 pointer = %#x, want 8-aligned", p) 2444 } 2445 2446 var unsigned struct { 2447 _ uint32 2448 i Uint64 2449 } 2450 if o := reflect.TypeOf(&unsigned).Elem().Field(1).Offset; o != 8 { 2451 t.Fatalf("Uint64 offset = %d, want 8", o) 2452 } 2453 if p := reflect.ValueOf(&unsigned).Elem().Field(1).Addr().Pointer(); p&7 != 0 { 2454 t.Fatalf("Int64 pointer = %#x, want 8-aligned", p) 2455 } 2456 } 2457 2458 func TestNilDeref(t *testing.T) { 2459 funcs := [...]func(){ 2460 func() { CompareAndSwapInt32(nil, 0, 0) }, 2461 func() { (*Int32)(nil).CompareAndSwap(0, 0) }, 2462 func() { CompareAndSwapInt64(nil, 0, 0) }, 2463 func() { (*Int64)(nil).CompareAndSwap(0, 0) }, 2464 func() { CompareAndSwapUint32(nil, 0, 0) }, 2465 func() { (*Uint32)(nil).CompareAndSwap(0, 0) }, 2466 func() { CompareAndSwapUint64(nil, 0, 0) }, 2467 func() { (*Uint64)(nil).CompareAndSwap(0, 0) }, 2468 func() { CompareAndSwapUintptr(nil, 0, 0) }, 2469 func() { (*Uintptr)(nil).CompareAndSwap(0, 0) }, 2470 func() { CompareAndSwapPointer(nil, nil, nil) }, 2471 func() { (*Pointer[byte])(nil).CompareAndSwap(nil, nil) }, 2472 func() { SwapInt32(nil, 0) }, 2473 func() { (*Int32)(nil).Swap(0) }, 2474 func() { SwapUint32(nil, 0) }, 2475 func() { (*Uint32)(nil).Swap(0) }, 2476 func() { SwapInt64(nil, 0) }, 2477 func() { (*Int64)(nil).Swap(0) }, 2478 func() { SwapUint64(nil, 0) }, 2479 func() { (*Uint64)(nil).Swap(0) }, 2480 func() { SwapUintptr(nil, 0) }, 2481 func() { (*Uintptr)(nil).Swap(0) }, 2482 func() { SwapPointer(nil, nil) }, 2483 func() { (*Pointer[byte])(nil).Swap(nil) }, 2484 func() { AddInt32(nil, 0) }, 2485 func() { (*Int32)(nil).Add(0) }, 2486 func() { AddUint32(nil, 0) }, 2487 func() { (*Uint32)(nil).Add(0) }, 2488 func() { AddInt64(nil, 0) }, 2489 func() { (*Int64)(nil).Add(0) }, 2490 func() { AddUint64(nil, 0) }, 2491 func() { (*Uint64)(nil).Add(0) }, 2492 func() { AddUintptr(nil, 0) }, 2493 func() { (*Uintptr)(nil).Add(0) }, 2494 func() { LoadInt32(nil) }, 2495 func() { (*Int32)(nil).Load() }, 2496 func() { LoadInt64(nil) }, 2497 func() { (*Int64)(nil).Load() }, 2498 func() { LoadUint32(nil) }, 2499 func() { (*Uint32)(nil).Load() }, 2500 func() { LoadUint64(nil) }, 2501 func() { (*Uint64)(nil).Load() }, 2502 func() { LoadUintptr(nil) }, 2503 func() { (*Uintptr)(nil).Load() }, 2504 func() { LoadPointer(nil) }, 2505 func() { (*Pointer[byte])(nil).Load() }, 2506 func() { StoreInt32(nil, 0) }, 2507 func() { (*Int32)(nil).Store(0) }, 2508 func() { StoreInt64(nil, 0) }, 2509 func() { (*Int64)(nil).Store(0) }, 2510 func() { StoreUint32(nil, 0) }, 2511 func() { (*Uint32)(nil).Store(0) }, 2512 func() { StoreUint64(nil, 0) }, 2513 func() { (*Uint64)(nil).Store(0) }, 2514 func() { StoreUintptr(nil, 0) }, 2515 func() { (*Uintptr)(nil).Store(0) }, 2516 func() { StorePointer(nil, nil) }, 2517 func() { (*Pointer[byte])(nil).Store(nil) }, 2518 } 2519 for _, f := range funcs { 2520 func() { 2521 defer func() { 2522 runtime.GC() 2523 recover() 2524 }() 2525 f() 2526 }() 2527 } 2528 } 2529 2530 // Test that this compiles. 2531 // When atomic.Pointer used _ [0]T, it did not. 2532 type List struct { 2533 Next Pointer[List] 2534 }