...
Run Format

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

View as plain text