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