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

View as plain text