OSDN Git Service

ad7557650f60895d95a2a7b79de6392e762cf18f
[pf3gnuchains/gcc-fork.git] / libgo / go / sync / atomic / atomic_test.go
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         "runtime"
9         . "sync/atomic"
10         "testing"
11         "unsafe"
12 )
13
14 // Tests of correct behavior, without contention.
15 // (Does the function work as advertised?)
16 //
17 // Test that the Add functions add correctly.
18 // Test that the CompareAndSwap functions actually
19 // do the comparison and the swap correctly.
20 //
21 // The loop over power-of-two values is meant to
22 // ensure that the operations apply to the full word size.
23 // The struct fields x.before and x.after check that the
24 // operations do not extend past the full word size.
25
26 const (
27         magic32 = 0xdedbeef
28         magic64 = 0xdeddeadbeefbeef
29 )
30
31 // Do the 64-bit functions panic?  If so, don't bother testing.
32 var test64err = func() (err interface{}) {
33         defer func() {
34                 err = recover()
35         }()
36         var x int64
37         AddInt64(&x, 1)
38         return nil
39 }()
40
41 func TestAddInt32(t *testing.T) {
42         var x struct {
43                 before int32
44                 i      int32
45                 after  int32
46         }
47         x.before = magic32
48         x.after = magic32
49         var j int32
50         for delta := int32(1); delta+delta > delta; delta += delta {
51                 k := AddInt32(&x.i, delta)
52                 j += delta
53                 if x.i != j || k != j {
54                         t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
55                 }
56         }
57         if x.before != magic32 || x.after != magic32 {
58                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
59         }
60 }
61
62 func TestAddUint32(t *testing.T) {
63         var x struct {
64                 before uint32
65                 i      uint32
66                 after  uint32
67         }
68         x.before = magic32
69         x.after = magic32
70         var j uint32
71         for delta := uint32(1); delta+delta > delta; delta += delta {
72                 k := AddUint32(&x.i, delta)
73                 j += delta
74                 if x.i != j || k != j {
75                         t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
76                 }
77         }
78         if x.before != magic32 || x.after != magic32 {
79                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
80         }
81 }
82
83 func TestAddInt64(t *testing.T) {
84         if test64err != nil {
85                 t.Logf("Skipping 64-bit tests: %v", test64err)
86                 return
87         }
88         var x struct {
89                 before int64
90                 i      int64
91                 after  int64
92         }
93         x.before = magic64
94         x.after = magic64
95         var j int64
96         for delta := int64(1); delta+delta > delta; delta += delta {
97                 k := AddInt64(&x.i, delta)
98                 j += delta
99                 if x.i != j || k != j {
100                         t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
101                 }
102         }
103         if x.before != magic64 || x.after != magic64 {
104                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, int64(magic64), int64(magic64))
105         }
106 }
107
108 func TestAddUint64(t *testing.T) {
109         if test64err != nil {
110                 t.Logf("Skipping 64-bit tests: %v", test64err)
111                 return
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 := AddUint64(&x.i, delta)
123                 j += delta
124                 if x.i != j || k != j {
125                         t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
126                 }
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 TestAddUintptr(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 := AddUintptr(&x.i, delta)
146                 j += delta
147                 if x.i != j || k != j {
148                         t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
149                 }
150         }
151         if x.before != magicptr || x.after != magicptr {
152                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
153         }
154 }
155
156 func TestCompareAndSwapInt32(t *testing.T) {
157         var x struct {
158                 before int32
159                 i      int32
160                 after  int32
161         }
162         x.before = magic32
163         x.after = magic32
164         for val := int32(1); val+val > val; val += val {
165                 x.i = val
166                 if !CompareAndSwapInt32(&x.i, val, val+1) {
167                         t.Fatalf("should have swapped %#x %#x", val, val+1)
168                 }
169                 if x.i != val+1 {
170                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
171                 }
172                 x.i = val + 1
173                 if CompareAndSwapInt32(&x.i, val, val+2) {
174                         t.Fatalf("should not have swapped %#x %#x", val, val+2)
175                 }
176                 if x.i != val+1 {
177                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
178                 }
179         }
180         if x.before != magic32 || x.after != magic32 {
181                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
182         }
183 }
184
185 func TestCompareAndSwapUint32(t *testing.T) {
186         var x struct {
187                 before uint32
188                 i      uint32
189                 after  uint32
190         }
191         x.before = magic32
192         x.after = magic32
193         for val := uint32(1); val+val > val; val += val {
194                 x.i = val
195                 if !CompareAndSwapUint32(&x.i, val, val+1) {
196                         t.Fatalf("should have swapped %#x %#x", val, val+1)
197                 }
198                 if x.i != val+1 {
199                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
200                 }
201                 x.i = val + 1
202                 if CompareAndSwapUint32(&x.i, val, val+2) {
203                         t.Fatalf("should not have swapped %#x %#x", val, val+2)
204                 }
205                 if x.i != val+1 {
206                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
207                 }
208         }
209         if x.before != magic32 || x.after != magic32 {
210                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
211         }
212 }
213
214 func TestCompareAndSwapInt64(t *testing.T) {
215         if test64err != nil {
216                 t.Logf("Skipping 64-bit tests: %v", test64err)
217                 return
218         }
219         var x struct {
220                 before int64
221                 i      int64
222                 after  int64
223         }
224         x.before = magic64
225         x.after = magic64
226         for val := int64(1); val+val > val; val += val {
227                 x.i = val
228                 if !CompareAndSwapInt64(&x.i, val, val+1) {
229                         t.Fatalf("should have swapped %#x %#x", val, val+1)
230                 }
231                 if x.i != val+1 {
232                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
233                 }
234                 x.i = val + 1
235                 if CompareAndSwapInt64(&x.i, val, val+2) {
236                         t.Fatalf("should not have swapped %#x %#x", val, val+2)
237                 }
238                 if x.i != val+1 {
239                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
240                 }
241         }
242         if x.before != magic64 || x.after != magic64 {
243                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
244         }
245 }
246
247 func TestCompareAndSwapUint64(t *testing.T) {
248         if test64err != nil {
249                 t.Logf("Skipping 64-bit tests: %v", test64err)
250                 return
251         }
252         var x struct {
253                 before uint64
254                 i      uint64
255                 after  uint64
256         }
257         x.before = magic64
258         x.after = magic64
259         for val := uint64(1); val+val > val; val += val {
260                 x.i = val
261                 if !CompareAndSwapUint64(&x.i, val, val+1) {
262                         t.Fatalf("should have swapped %#x %#x", val, val+1)
263                 }
264                 if x.i != val+1 {
265                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
266                 }
267                 x.i = val + 1
268                 if CompareAndSwapUint64(&x.i, val, val+2) {
269                         t.Fatalf("should not have swapped %#x %#x", val, val+2)
270                 }
271                 if x.i != val+1 {
272                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
273                 }
274         }
275         if x.before != magic64 || x.after != magic64 {
276                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
277         }
278 }
279
280 func TestCompareAndSwapUintptr(t *testing.T) {
281         var x struct {
282                 before uintptr
283                 i      uintptr
284                 after  uintptr
285         }
286         var m uint64 = magic64
287         magicptr := uintptr(m)
288         x.before = magicptr
289         x.after = magicptr
290         for val := uintptr(1); val+val > val; val += val {
291                 x.i = val
292                 if !CompareAndSwapUintptr(&x.i, val, val+1) {
293                         t.Fatalf("should have swapped %#x %#x", val, val+1)
294                 }
295                 if x.i != val+1 {
296                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
297                 }
298                 x.i = val + 1
299                 if CompareAndSwapUintptr(&x.i, val, val+2) {
300                         t.Fatalf("should not have swapped %#x %#x", val, val+2)
301                 }
302                 if x.i != val+1 {
303                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
304                 }
305         }
306         if x.before != magicptr || x.after != magicptr {
307                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
308         }
309 }
310
311 func TestCompareAndSwapPointer(t *testing.T) {
312         var x struct {
313                 before uintptr
314                 i      unsafe.Pointer
315                 after  uintptr
316         }
317         var m uint64 = magic64
318         magicptr := uintptr(m)
319         x.before = magicptr
320         x.after = magicptr
321         for val := uintptr(1); val+val > val; val += val {
322                 x.i = unsafe.Pointer(val)
323                 if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) {
324                         t.Fatalf("should have swapped %#x %#x", val, val+1)
325                 }
326                 if x.i != unsafe.Pointer(val+1) {
327                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
328                 }
329                 x.i = unsafe.Pointer(val + 1)
330                 if CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+2)) {
331                         t.Fatalf("should not have swapped %#x %#x", val, val+2)
332                 }
333                 if x.i != unsafe.Pointer(val+1) {
334                         t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
335                 }
336         }
337         if x.before != magicptr || x.after != magicptr {
338                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
339         }
340 }
341
342 func TestLoadInt32(t *testing.T) {
343         var x struct {
344                 before int32
345                 i      int32
346                 after  int32
347         }
348         x.before = magic32
349         x.after = magic32
350         for delta := int32(1); delta+delta > delta; delta += delta {
351                 k := LoadInt32(&x.i)
352                 if k != x.i {
353                         t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
354                 }
355                 x.i += delta
356         }
357         if x.before != magic32 || x.after != magic32 {
358                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
359         }
360 }
361
362 func TestLoadUint32(t *testing.T) {
363         var x struct {
364                 before uint32
365                 i      uint32
366                 after  uint32
367         }
368         x.before = magic32
369         x.after = magic32
370         for delta := uint32(1); delta+delta > delta; delta += delta {
371                 k := LoadUint32(&x.i)
372                 if k != x.i {
373                         t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
374                 }
375                 x.i += delta
376         }
377         if x.before != magic32 || x.after != magic32 {
378                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
379         }
380 }
381
382 func TestLoadInt64(t *testing.T) {
383         if test64err != nil {
384                 t.Logf("Skipping 64-bit tests: %v", test64err)
385                 return
386         }
387         var x struct {
388                 before int64
389                 i      int64
390                 after  int64
391         }
392         x.before = magic64
393         x.after = magic64
394         for delta := int64(1); delta+delta > delta; delta += delta {
395                 k := LoadInt64(&x.i)
396                 if k != x.i {
397                         t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
398                 }
399                 x.i += delta
400         }
401         if x.before != magic64 || x.after != magic64 {
402                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
403         }
404 }
405
406 func TestLoadUint64(t *testing.T) {
407         if test64err != nil {
408                 t.Logf("Skipping 64-bit tests: %v", test64err)
409                 return
410         }
411         var x struct {
412                 before uint64
413                 i      uint64
414                 after  uint64
415         }
416         x.before = magic64
417         x.after = magic64
418         for delta := uint64(1); delta+delta > delta; delta += delta {
419                 k := LoadUint64(&x.i)
420                 if k != x.i {
421                         t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
422                 }
423                 x.i += delta
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 TestLoadUintptr(t *testing.T) {
431         var x struct {
432                 before uintptr
433                 i      uintptr
434                 after  uintptr
435         }
436         var m uint64 = magic64
437         magicptr := uintptr(m)
438         x.before = magicptr
439         x.after = magicptr
440         for delta := uintptr(1); delta+delta > delta; delta += delta {
441                 k := LoadUintptr(&x.i)
442                 if k != x.i {
443                         t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
444                 }
445                 x.i += delta
446         }
447         if x.before != magicptr || x.after != magicptr {
448                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
449         }
450 }
451
452 func TestLoadPointer(t *testing.T) {
453         var x struct {
454                 before uintptr
455                 i      unsafe.Pointer
456                 after  uintptr
457         }
458         var m uint64 = magic64
459         magicptr := uintptr(m)
460         x.before = magicptr
461         x.after = magicptr
462         for delta := uintptr(1); delta+delta > delta; delta += delta {
463                 k := LoadPointer(&x.i)
464                 if k != x.i {
465                         t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
466                 }
467                 x.i = unsafe.Pointer(uintptr(x.i) + delta)
468         }
469         if x.before != magicptr || x.after != magicptr {
470                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
471         }
472 }
473
474 func TestStoreInt32(t *testing.T) {
475         var x struct {
476                 before int32
477                 i      int32
478                 after  int32
479         }
480         x.before = magic32
481         x.after = magic32
482         v := int32(0)
483         for delta := int32(1); delta+delta > delta; delta += delta {
484                 StoreInt32(&x.i, v)
485                 if x.i != v {
486                         t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
487                 }
488                 v += delta
489         }
490         if x.before != magic32 || x.after != magic32 {
491                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
492         }
493 }
494
495 func TestStoreUint32(t *testing.T) {
496         var x struct {
497                 before uint32
498                 i      uint32
499                 after  uint32
500         }
501         x.before = magic32
502         x.after = magic32
503         v := uint32(0)
504         for delta := uint32(1); delta+delta > delta; delta += delta {
505                 StoreUint32(&x.i, v)
506                 if x.i != v {
507                         t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
508                 }
509                 v += 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 TestStoreInt64(t *testing.T) {
517         if test64err != nil {
518                 t.Logf("Skipping 64-bit tests: %v", test64err)
519                 return
520         }
521         var x struct {
522                 before int64
523                 i      int64
524                 after  int64
525         }
526         x.before = magic64
527         x.after = magic64
528         v := int64(0)
529         for delta := int64(1); delta+delta > delta; delta += delta {
530                 StoreInt64(&x.i, v)
531                 if x.i != v {
532                         t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
533                 }
534                 v += delta
535         }
536         if x.before != magic64 || x.after != magic64 {
537                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
538         }
539 }
540
541 func TestStoreUint64(t *testing.T) {
542         if test64err != nil {
543                 t.Logf("Skipping 64-bit tests: %v", test64err)
544                 return
545         }
546         var x struct {
547                 before uint64
548                 i      uint64
549                 after  uint64
550         }
551         x.before = magic64
552         x.after = magic64
553         v := uint64(0)
554         for delta := uint64(1); delta+delta > delta; delta += delta {
555                 StoreUint64(&x.i, v)
556                 if x.i != v {
557                         t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
558                 }
559                 v += delta
560         }
561         if x.before != magic64 || x.after != magic64 {
562                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
563         }
564 }
565
566 func TestStoreUintptr(t *testing.T) {
567         var x struct {
568                 before uintptr
569                 i      uintptr
570                 after  uintptr
571         }
572         var m uint64 = magic64
573         magicptr := uintptr(m)
574         x.before = magicptr
575         x.after = magicptr
576         v := uintptr(0)
577         for delta := uintptr(1); delta+delta > delta; delta += delta {
578                 StoreUintptr(&x.i, v)
579                 if x.i != v {
580                         t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
581                 }
582                 v += delta
583         }
584         if x.before != magicptr || x.after != magicptr {
585                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
586         }
587 }
588
589 func TestStorePointer(t *testing.T) {
590         var x struct {
591                 before uintptr
592                 i      unsafe.Pointer
593                 after  uintptr
594         }
595         var m uint64 = magic64
596         magicptr := uintptr(m)
597         x.before = magicptr
598         x.after = magicptr
599         v := unsafe.Pointer(uintptr(0))
600         for delta := uintptr(1); delta+delta > delta; delta += delta {
601                 StorePointer(&x.i, unsafe.Pointer(v))
602                 if x.i != v {
603                         t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
604                 }
605                 v = unsafe.Pointer(uintptr(v) + delta)
606         }
607         if x.before != magicptr || x.after != magicptr {
608                 t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
609         }
610 }
611
612 // Tests of correct behavior, with contention.
613 // (Is the function atomic?)
614 //
615 // For each function, we write a "hammer" function that repeatedly
616 // uses the atomic operation to add 1 to a value.  After running
617 // multiple hammers in parallel, check that we end with the correct
618 // total.
619
620 var hammer32 = []struct {
621         name string
622         f    func(*uint32, int)
623 }{
624         {"AddInt32", hammerAddInt32},
625         {"AddUint32", hammerAddUint32},
626         {"AddUintptr", hammerAddUintptr32},
627         {"CompareAndSwapInt32", hammerCompareAndSwapInt32},
628         {"CompareAndSwapUint32", hammerCompareAndSwapUint32},
629         {"CompareAndSwapUintptr", hammerCompareAndSwapUintptr32},
630         {"CompareAndSwapPointer", hammerCompareAndSwapPointer32},
631 }
632
633 func init() {
634         var v uint64 = 1 << 50
635         if uintptr(v) != 0 {
636                 // 64-bit system; clear uintptr tests
637                 hammer32[2].f = nil
638                 hammer32[5].f = nil
639         }
640 }
641
642 func hammerAddInt32(uval *uint32, count int) {
643         val := (*int32)(unsafe.Pointer(uval))
644         for i := 0; i < count; i++ {
645                 AddInt32(val, 1)
646         }
647 }
648
649 func hammerAddUint32(val *uint32, count int) {
650         for i := 0; i < count; i++ {
651                 AddUint32(val, 1)
652         }
653 }
654
655 func hammerAddUintptr32(uval *uint32, count int) {
656         // only safe when uintptr is 32-bit.
657         // not called on 64-bit systems.
658         val := (*uintptr)(unsafe.Pointer(uval))
659         for i := 0; i < count; i++ {
660                 AddUintptr(val, 1)
661         }
662 }
663
664 func hammerCompareAndSwapInt32(uval *uint32, count int) {
665         val := (*int32)(unsafe.Pointer(uval))
666         for i := 0; i < count; i++ {
667                 for {
668                         v := *val
669                         if CompareAndSwapInt32(val, v, v+1) {
670                                 break
671                         }
672                 }
673         }
674 }
675
676 func hammerCompareAndSwapUint32(val *uint32, count int) {
677         for i := 0; i < count; i++ {
678                 for {
679                         v := *val
680                         if CompareAndSwapUint32(val, v, v+1) {
681                                 break
682                         }
683                 }
684         }
685 }
686
687 func hammerCompareAndSwapUintptr32(uval *uint32, count int) {
688         // only safe when uintptr is 32-bit.
689         // not called on 64-bit systems.
690         val := (*uintptr)(unsafe.Pointer(uval))
691         for i := 0; i < count; i++ {
692                 for {
693                         v := *val
694                         if CompareAndSwapUintptr(val, v, v+1) {
695                                 break
696                         }
697                 }
698         }
699 }
700
701 func hammerCompareAndSwapPointer32(uval *uint32, count int) {
702         // only safe when uintptr is 32-bit.
703         // not called on 64-bit systems.
704         val := (*unsafe.Pointer)(unsafe.Pointer(uval))
705         for i := 0; i < count; i++ {
706                 for {
707                         v := *val
708                         if CompareAndSwapPointer(val, v, unsafe.Pointer(uintptr(v)+1)) {
709                                 break
710                         }
711                 }
712         }
713 }
714
715 func TestHammer32(t *testing.T) {
716         const p = 4
717         n := 100000
718         if testing.Short() {
719                 n = 1000
720         }
721         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p))
722
723         for _, tt := range hammer32 {
724                 if tt.f == nil {
725                         continue
726                 }
727                 c := make(chan int)
728                 var val uint32
729                 for i := 0; i < p; i++ {
730                         go func() {
731                                 tt.f(&val, n)
732                                 c <- 1
733                         }()
734                 }
735                 for i := 0; i < p; i++ {
736                         <-c
737                 }
738                 if val != uint32(n)*p {
739                         t.Fatalf("%s: val=%d want %d", tt.name, val, n*p)
740                 }
741         }
742 }
743
744 var hammer64 = []struct {
745         name string
746         f    func(*uint64, int)
747 }{
748         {"AddInt64", hammerAddInt64},
749         {"AddUint64", hammerAddUint64},
750         {"AddUintptr", hammerAddUintptr64},
751         {"CompareAndSwapInt64", hammerCompareAndSwapInt64},
752         {"CompareAndSwapUint64", hammerCompareAndSwapUint64},
753         {"CompareAndSwapUintptr", hammerCompareAndSwapUintptr64},
754         {"CompareAndSwapPointer", hammerCompareAndSwapPointer64},
755 }
756
757 func init() {
758         var v uint64 = 1 << 50
759         if uintptr(v) == 0 {
760                 // 32-bit system; clear uintptr tests
761                 hammer64[2].f = nil
762                 hammer64[5].f = nil
763         }
764 }
765
766 func hammerAddInt64(uval *uint64, count int) {
767         val := (*int64)(unsafe.Pointer(uval))
768         for i := 0; i < count; i++ {
769                 AddInt64(val, 1)
770         }
771 }
772
773 func hammerAddUint64(val *uint64, count int) {
774         for i := 0; i < count; i++ {
775                 AddUint64(val, 1)
776         }
777 }
778
779 func hammerAddUintptr64(uval *uint64, count int) {
780         // only safe when uintptr is 64-bit.
781         // not called on 32-bit systems.
782         val := (*uintptr)(unsafe.Pointer(uval))
783         for i := 0; i < count; i++ {
784                 AddUintptr(val, 1)
785         }
786 }
787
788 func hammerCompareAndSwapInt64(uval *uint64, count int) {
789         val := (*int64)(unsafe.Pointer(uval))
790         for i := 0; i < count; i++ {
791                 for {
792                         v := *val
793                         if CompareAndSwapInt64(val, v, v+1) {
794                                 break
795                         }
796                 }
797         }
798 }
799
800 func hammerCompareAndSwapUint64(val *uint64, count int) {
801         for i := 0; i < count; i++ {
802                 for {
803                         v := *val
804                         if CompareAndSwapUint64(val, v, v+1) {
805                                 break
806                         }
807                 }
808         }
809 }
810
811 func hammerCompareAndSwapUintptr64(uval *uint64, count int) {
812         // only safe when uintptr is 64-bit.
813         // not called on 32-bit systems.
814         val := (*uintptr)(unsafe.Pointer(uval))
815         for i := 0; i < count; i++ {
816                 for {
817                         v := *val
818                         if CompareAndSwapUintptr(val, v, v+1) {
819                                 break
820                         }
821                 }
822         }
823 }
824
825 func hammerCompareAndSwapPointer64(uval *uint64, count int) {
826         // only safe when uintptr is 64-bit.
827         // not called on 32-bit systems.
828         val := (*unsafe.Pointer)(unsafe.Pointer(uval))
829         for i := 0; i < count; i++ {
830                 for {
831                         v := *val
832                         if CompareAndSwapPointer(val, v, unsafe.Pointer(uintptr(v)+1)) {
833                                 break
834                         }
835                 }
836         }
837 }
838
839 func TestHammer64(t *testing.T) {
840         if test64err != nil {
841                 t.Logf("Skipping 64-bit tests: %v", test64err)
842                 return
843         }
844         const p = 4
845         n := 100000
846         if testing.Short() {
847                 n = 1000
848         }
849         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p))
850
851         for _, tt := range hammer64 {
852                 if tt.f == nil {
853                         continue
854                 }
855                 c := make(chan int)
856                 var val uint64
857                 for i := 0; i < p; i++ {
858                         go func() {
859                                 tt.f(&val, n)
860                                 c <- 1
861                         }()
862                 }
863                 for i := 0; i < p; i++ {
864                         <-c
865                 }
866                 if val != uint64(n)*p {
867                         t.Fatalf("%s: val=%d want %d", tt.name, val, n*p)
868                 }
869         }
870 }
871
872 func hammerStoreLoadInt32(t *testing.T, valp unsafe.Pointer) {
873         val := (*int32)(valp)
874         v := LoadInt32(val)
875         vlo := v & ((1 << 16) - 1)
876         vhi := v >> 16
877         if vlo != vhi {
878                 t.Fatalf("Int32: %#x != %#x", vlo, vhi)
879         }
880         new := v + 1 + 1<<16
881         if vlo == 1e4 {
882                 new = 0
883         }
884         StoreInt32(val, new)
885 }
886
887 func hammerStoreLoadUint32(t *testing.T, valp unsafe.Pointer) {
888         val := (*uint32)(valp)
889         v := LoadUint32(val)
890         vlo := v & ((1 << 16) - 1)
891         vhi := v >> 16
892         if vlo != vhi {
893                 t.Fatalf("Uint32: %#x != %#x", vlo, vhi)
894         }
895         new := v + 1 + 1<<16
896         if vlo == 1e4 {
897                 new = 0
898         }
899         StoreUint32(val, new)
900 }
901
902 func hammerStoreLoadInt64(t *testing.T, valp unsafe.Pointer) {
903         val := (*int64)(valp)
904         v := LoadInt64(val)
905         vlo := v & ((1 << 32) - 1)
906         vhi := v >> 32
907         if vlo != vhi {
908                 t.Fatalf("Int64: %#x != %#x", vlo, vhi)
909         }
910         new := v + 1 + 1<<32
911         StoreInt64(val, new)
912 }
913
914 func hammerStoreLoadUint64(t *testing.T, valp unsafe.Pointer) {
915         val := (*uint64)(valp)
916         v := LoadUint64(val)
917         vlo := v & ((1 << 32) - 1)
918         vhi := v >> 32
919         if vlo != vhi {
920                 t.Fatalf("Uint64: %#x != %#x", vlo, vhi)
921         }
922         new := v + 1 + 1<<32
923         StoreUint64(val, new)
924 }
925
926 func hammerStoreLoadUintptr(t *testing.T, valp unsafe.Pointer) {
927         val := (*uintptr)(valp)
928         var test64 uint64 = 1 << 50
929         arch32 := uintptr(test64) == 0
930         v := LoadUintptr(val)
931         new := v
932         if arch32 {
933                 vlo := v & ((1 << 16) - 1)
934                 vhi := v >> 16
935                 if vlo != vhi {
936                         t.Fatalf("Uintptr: %#x != %#x", vlo, vhi)
937                 }
938                 new = v + 1 + 1<<16
939                 if vlo == 1e4 {
940                         new = 0
941                 }
942         } else {
943                 vlo := v & ((1 << 32) - 1)
944                 vhi := v >> 32
945                 if vlo != vhi {
946                         t.Fatalf("Uintptr: %#x != %#x", vlo, vhi)
947                 }
948                 inc := uint64(1 + 1<<32)
949                 new = v + uintptr(inc)
950         }
951         StoreUintptr(val, new)
952 }
953
954 func hammerStoreLoadPointer(t *testing.T, valp unsafe.Pointer) {
955         val := (*unsafe.Pointer)(valp)
956         var test64 uint64 = 1 << 50
957         arch32 := uintptr(test64) == 0
958         v := uintptr(LoadPointer(val))
959         new := v
960         if arch32 {
961                 vlo := v & ((1 << 16) - 1)
962                 vhi := v >> 16
963                 if vlo != vhi {
964                         t.Fatalf("Pointer: %#x != %#x", vlo, vhi)
965                 }
966                 new = v + 1 + 1<<16
967                 if vlo == 1e4 {
968                         new = 0
969                 }
970         } else {
971                 vlo := v & ((1 << 32) - 1)
972                 vhi := v >> 32
973                 if vlo != vhi {
974                         t.Fatalf("Pointer: %#x != %#x", vlo, vhi)
975                 }
976                 inc := uint64(1 + 1<<32)
977                 new = v + uintptr(inc)
978         }
979         StorePointer(val, unsafe.Pointer(new))
980 }
981
982 func TestHammerStoreLoad(t *testing.T) {
983         var tests []func(*testing.T, unsafe.Pointer)
984         tests = append(tests, hammerStoreLoadInt32, hammerStoreLoadUint32,
985                 hammerStoreLoadUintptr, hammerStoreLoadPointer)
986         if test64err == nil {
987                 tests = append(tests, hammerStoreLoadInt64, hammerStoreLoadUint64)
988         }
989         n := int(1e6)
990         if testing.Short() {
991                 n = int(1e4)
992         }
993         const procs = 8
994         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
995         for _, tt := range tests {
996                 c := make(chan int)
997                 var val uint64
998                 for p := 0; p < procs; p++ {
999                         go func() {
1000                                 for i := 0; i < n; i++ {
1001                                         tt(t, unsafe.Pointer(&val))
1002                                 }
1003                                 c <- 1
1004                         }()
1005                 }
1006                 for p := 0; p < procs; p++ {
1007                         <-c
1008                 }
1009         }
1010 }
1011
1012 func TestStoreLoadSeqCst32(t *testing.T) {
1013         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
1014         N := int32(1e3)
1015         if testing.Short() {
1016                 N = int32(1e2)
1017         }
1018         c := make(chan bool, 2)
1019         X := [2]int32{}
1020         ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}}
1021         for p := 0; p < 2; p++ {
1022                 go func(me int) {
1023                         he := 1 - me
1024                         for i := int32(1); i < N; i++ {
1025                                 StoreInt32(&X[me], i)
1026                                 my := LoadInt32(&X[he])
1027                                 StoreInt32(&ack[me][i%3], my)
1028                                 for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ {
1029                                         if w%1000 == 0 {
1030                                                 runtime.Gosched()
1031                                         }
1032                                 }
1033                                 his := LoadInt32(&ack[he][i%3])
1034                                 if (my != i && my != i-1) || (his != i && his != i-1) {
1035                                         t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
1036                                 }
1037                                 if my != i && his != i {
1038                                         t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
1039                                 }
1040                                 StoreInt32(&ack[me][(i-1)%3], -1)
1041                         }
1042                         c <- true
1043                 }(p)
1044         }
1045         <-c
1046         <-c
1047 }
1048
1049 func TestStoreLoadSeqCst64(t *testing.T) {
1050         if test64err != nil {
1051                 t.Logf("Skipping 64-bit tests: %v", test64err)
1052                 return
1053         }
1054         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
1055         N := int64(1e3)
1056         if testing.Short() {
1057                 N = int64(1e2)
1058         }
1059         c := make(chan bool, 2)
1060         X := [2]int64{}
1061         ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}}
1062         for p := 0; p < 2; p++ {
1063                 go func(me int) {
1064                         he := 1 - me
1065                         for i := int64(1); i < N; i++ {
1066                                 StoreInt64(&X[me], i)
1067                                 my := LoadInt64(&X[he])
1068                                 StoreInt64(&ack[me][i%3], my)
1069                                 for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ {
1070                                         if w%1000 == 0 {
1071                                                 runtime.Gosched()
1072                                         }
1073                                 }
1074                                 his := LoadInt64(&ack[he][i%3])
1075                                 if (my != i && my != i-1) || (his != i && his != i-1) {
1076                                         t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
1077                                 }
1078                                 if my != i && his != i {
1079                                         t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
1080                                 }
1081                                 StoreInt64(&ack[me][(i-1)%3], -1)
1082                         }
1083                         c <- true
1084                 }(p)
1085         }
1086         <-c
1087         <-c
1088 }
1089
1090 func TestStoreLoadRelAcq32(t *testing.T) {
1091         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
1092         N := int32(1e3)
1093         if testing.Short() {
1094                 N = int32(1e2)
1095         }
1096         c := make(chan bool, 2)
1097         type Data struct {
1098                 signal int32
1099                 pad1   [128]int8
1100                 data1  int32
1101                 pad2   [128]int8
1102                 data2  float32
1103         }
1104         var X Data
1105         for p := int32(0); p < 2; p++ {
1106                 go func(p int32) {
1107                         for i := int32(1); i < N; i++ {
1108                                 if (i+p)%2 == 0 {
1109                                         X.data1 = i
1110                                         X.data2 = float32(i)
1111                                         StoreInt32(&X.signal, i)
1112                                 } else {
1113                                         for w := 1; LoadInt32(&X.signal) != i; w++ {
1114                                                 if w%1000 == 0 {
1115                                                         runtime.Gosched()
1116                                                 }
1117                                         }
1118                                         d1 := X.data1
1119                                         d2 := X.data2
1120                                         if d1 != i || d2 != float32(i) {
1121                                                 t.Fatalf("incorrect data: %d/%d (%d)", d1, d2, i)
1122                                         }
1123                                 }
1124                         }
1125                         c <- true
1126                 }(p)
1127         }
1128         <-c
1129         <-c
1130 }
1131
1132 func TestStoreLoadRelAcq64(t *testing.T) {
1133         if test64err != nil {
1134                 t.Logf("Skipping 64-bit tests: %v", test64err)
1135                 return
1136         }
1137         defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
1138         N := int64(1e3)
1139         if testing.Short() {
1140                 N = int64(1e2)
1141         }
1142         c := make(chan bool, 2)
1143         type Data struct {
1144                 signal int64
1145                 pad1   [128]int8
1146                 data1  int64
1147                 pad2   [128]int8
1148                 data2  float64
1149         }
1150         var X Data
1151         for p := int64(0); p < 2; p++ {
1152                 go func(p int64) {
1153                         for i := int64(1); i < N; i++ {
1154                                 if (i+p)%2 == 0 {
1155                                         X.data1 = i
1156                                         X.data2 = float64(i)
1157                                         StoreInt64(&X.signal, i)
1158                                 } else {
1159                                         for w := 1; LoadInt64(&X.signal) != i; w++ {
1160                                                 if w%1000 == 0 {
1161                                                         runtime.Gosched()
1162                                                 }
1163                                         }
1164                                         d1 := X.data1
1165                                         d2 := X.data2
1166                                         if d1 != i || d2 != float64(i) {
1167                                                 t.Fatalf("incorrect data: %d/%d (%d)", d1, d2, i)
1168                                         }
1169                                 }
1170                         }
1171                         c <- true
1172                 }(p)
1173         }
1174         <-c
1175         <-c
1176 }