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