Black Lives Matter. Support the Equal Justice Initiative.

Source file src/sync/atomic/atomic_test.go

Documentation: sync/atomic

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package atomic_test
     6  
     7  import (
     8  	"fmt"
     9  	"runtime"
    10  	"strings"
    11  	. "sync/atomic"
    12  	"testing"
    13  	"unsafe"
    14  )
    15  
    16  // Tests of correct behavior, without contention.
    17  // (Does the function work as advertised?)
    18  //
    19  // Test that the Add functions add correctly.
    20  // Test that the CompareAndSwap functions actually
    21  // do the comparison and the swap correctly.
    22  //
    23  // The loop over power-of-two values is meant to
    24  // ensure that the operations apply to the full word size.
    25  // The struct fields x.before and x.after check that the
    26  // operations do not extend past the full word size.
    27  
    28  const (
    29  	magic32 = 0xdedbeef
    30  	magic64 = 0xdeddeadbeefbeef
    31  )
    32  
    33  // Do the 64-bit functions panic? If so, don't bother testing.
    34  var test64err = func() (err interface{}) {
    35  	defer func() {
    36  		err = recover()
    37  	}()
    38  	var x int64
    39  	AddInt64(&x, 1)
    40  	return nil
    41  }()
    42  
    43  func TestSwapInt32(t *testing.T) {
    44  	var x struct {
    45  		before int32
    46  		i      int32
    47  		after  int32
    48  	}
    49  	x.before = magic32
    50  	x.after = magic32
    51  	var j int32
    52  	for delta := int32(1); delta+delta > delta; delta += delta {
    53  		k := SwapInt32(&x.i, delta)
    54  		if x.i != delta || k != j {
    55  			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
    56  		}
    57  		j = delta
    58  	}
    59  	if x.before != magic32 || x.after != magic32 {
    60  		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
    61  	}
    62  }
    63  
    64  func TestSwapUint32(t *testing.T) {
    65  	var x struct {
    66  		before uint32
    67  		i      uint32
    68  		after  uint32
    69  	}
    70  	x.before = magic32
    71  	x.after = magic32
    72  	var j uint32
    73  	for delta := uint32(1); delta+delta > delta; delta += delta {
    74  		k := SwapUint32(&x.i, delta)
    75  		if x.i != delta || k != j {
    76  			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
    77  		}
    78  		j = delta
    79  	}
    80  	if x.before != magic32 || x.after != magic32 {
    81  		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
    82  	}
    83  }
    84  
    85  func TestSwapInt64(t *testing.T) {
    86  	if test64err != nil {
    87  		t.Skipf("Skipping 64-bit tests: %v", test64err)
    88  	}
    89  	var x struct {
    90  		before int64
    91  		i      int64
    92  		after  int64
    93  	}
    94  	x.before = magic64
    95  	x.after = magic64
    96  	var j int64
    97  	for delta := int64(1); delta+delta > delta; delta += delta {
    98  		k := SwapInt64(&x.i, delta)
    99  		if x.i != delta || k != j {
   100  			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
   101  		}
   102  		j = delta
   103  	}
   104  	if x.before != magic64 || x.after != magic64 {
   105  		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
   106  	}
   107  }
   108  
   109  func TestSwapUint64(t *testing.T) {
   110  	if test64err != nil {
   111  		t.Skipf("Skipping 64-bit tests: %v", test64err)
   112  	}
   113  	var x struct {
   114  		before uint64
   115  		i      uint64
   116  		after  uint64
   117  	}
   118  	x.before = magic64
   119  	x.after = magic64
   120  	var j uint64
   121  	for delta := uint64(1); delta+delta > delta; delta += delta {
   122  		k := SwapUint64(&x.i, delta)
   123  		if x.i != delta || k != j {
   124  			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
   125  		}
   126  		j = delta
   127  	}
   128  	if x.before != magic64 || x.after != magic64 {
   129  		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
   130  	}
   131  }
   132  
   133  func TestSwapUintptr(t *testing.T) {
   134  	var x struct {
   135  		before uintptr
   136  		i      uintptr
   137  		after  uintptr
   138  	}
   139  	var m uint64 = magic64
   140  	magicptr := uintptr(m)
   141  	x.before = magicptr
   142  	x.after = magicptr
   143  	var j uintptr
   144  	for delta := uintptr(1); delta+delta > delta; delta += delta {
   145  		k := SwapUintptr(&x.i, delta)
   146  		if x.i != delta || k != j {
   147  			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
   148  		}
   149  		j = delta
   150  	}
   151  	if x.before != magicptr || x.after != magicptr {
   152  		t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
   153  	}
   154  }
   155  
   156  var global [1024]byte
   157  
   158  func testPointers() []unsafe.Pointer {
   159  	var pointers []unsafe.Pointer
   160  	// globals
   161  	for i := 0; i < 10; i++ {
   162  		pointers = append(pointers, unsafe.Pointer(&global[1<<i-1]))
   163  	}
   164  	// heap
   165  	pointers = append(pointers, unsafe.Pointer(new(byte)))
   166  	// nil
   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  // Tests of correct behavior, with contention.
   761  // (Is the function atomic?)
   762  //
   763  // For each function, we write a "hammer" function that repeatedly
   764  // uses the atomic operation to add 1 to a value. After running
   765  // multiple hammers in parallel, check that we end with the correct
   766  // total.
   767  // Swap can't add 1, so it uses a different scheme.
   768  // The functions repeatedly generate a pseudo-random number such that
   769  // low bits are equal to high bits, swap, check that the old value
   770  // has low and high bits equal.
   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  		// 64-bit system; clear uintptr tests
   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  	// only safe when uintptr is 32-bit.
   819  	// not called on 64-bit systems.
   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  	// only safe when uintptr is 32-bit.
   846  	// not called on 64-bit systems.
   847  	addr := (*uintptr)(unsafe.Pointer(uaddr))
   848  	for i := 0; i < count; i++ {
   849  		AddUintptr(addr, 1)
   850  	}
   851  }
   852  
   853  func hammerCompareAndSwapInt32(uaddr *uint32, count int) {
   854  	addr := (*int32)(unsafe.Pointer(uaddr))
   855  	for i := 0; i < count; i++ {
   856  		for {
   857  			v := 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  	// only safe when uintptr is 32-bit.
   878  	// not called on 64-bit systems.
   879  	addr := (*uintptr)(unsafe.Pointer(uaddr))
   880  	for i := 0; i < count; i++ {
   881  		for {
   882  			v := 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  		// 32-bit system; clear uintptr tests
   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  	// only safe when uintptr is 64-bit.
   970  	// not called on 32-bit systems.
   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  	// only safe when uintptr is 64-bit.
   999  	// not called on 32-bit systems.
  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  	// only safe when uintptr is 64-bit.
  1031  	// not called on 32-bit systems.
  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  //go:nocheckptr
  1158  // This code is just testing that LoadPointer/StorePointer operate
  1159  // atomically; it's not actually calculating pointers.
  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  		// Check that all GC maps are sane.
  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  	// Unaligned 64-bit atomics on 32-bit systems are
  1416  	// a continual source of pain. Test that on 32-bit systems they crash
  1417  	// instead of failing silently.
  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])) // misaligned
  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