github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/atomicbitops/atomicbitops_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package atomicbitops
    16  
    17  import (
    18  	"runtime"
    19  	"testing"
    20  
    21  	"github.com/SagerNet/gvisor/pkg/sync"
    22  )
    23  
    24  const iterations = 100
    25  
    26  func detectRaces32(val, target uint32, fn func(*uint32, uint32)) bool {
    27  	runtime.GOMAXPROCS(100)
    28  	for n := 0; n < iterations; n++ {
    29  		x := val
    30  		var wg sync.WaitGroup
    31  		for i := uint32(0); i < 32; i++ {
    32  			wg.Add(1)
    33  			go func(a *uint32, i uint32) {
    34  				defer wg.Done()
    35  				fn(a, uint32(1<<i))
    36  			}(&x, i)
    37  		}
    38  		wg.Wait()
    39  		if x != target {
    40  			return true
    41  		}
    42  	}
    43  	return false
    44  }
    45  
    46  func detectRaces64(val, target uint64, fn func(*uint64, uint64)) bool {
    47  	runtime.GOMAXPROCS(100)
    48  	for n := 0; n < iterations; n++ {
    49  		x := val
    50  		var wg sync.WaitGroup
    51  		for i := uint64(0); i < 64; i++ {
    52  			wg.Add(1)
    53  			go func(a *uint64, i uint64) {
    54  				defer wg.Done()
    55  				fn(a, uint64(1<<i))
    56  			}(&x, i)
    57  		}
    58  		wg.Wait()
    59  		if x != target {
    60  			return true
    61  		}
    62  	}
    63  	return false
    64  }
    65  
    66  func TestOrUint32(t *testing.T) {
    67  	if detectRaces32(0x0, 0xffffffff, OrUint32) {
    68  		t.Error("Data race detected!")
    69  	}
    70  }
    71  
    72  func TestAndUint32(t *testing.T) {
    73  	if detectRaces32(0xf0f0f0f0, 0x00000000, AndUint32) {
    74  		t.Error("Data race detected!")
    75  	}
    76  }
    77  
    78  func TestXorUint32(t *testing.T) {
    79  	if detectRaces32(0xf0f0f0f0, 0x0f0f0f0f, XorUint32) {
    80  		t.Error("Data race detected!")
    81  	}
    82  }
    83  
    84  func TestOrUint64(t *testing.T) {
    85  	if detectRaces64(0x0, 0xffffffffffffffff, OrUint64) {
    86  		t.Error("Data race detected!")
    87  	}
    88  }
    89  
    90  func TestAndUint64(t *testing.T) {
    91  	if detectRaces64(0xf0f0f0f0f0f0f0f0, 0x0, AndUint64) {
    92  		t.Error("Data race detected!")
    93  	}
    94  }
    95  
    96  func TestXorUint64(t *testing.T) {
    97  	if detectRaces64(0xf0f0f0f0f0f0f0f0, 0x0f0f0f0f0f0f0f0f, XorUint64) {
    98  		t.Error("Data race detected!")
    99  	}
   100  }
   101  
   102  func TestCompareAndSwapUint32(t *testing.T) {
   103  	tests := []struct {
   104  		name string
   105  		prev uint32
   106  		old  uint32
   107  		new  uint32
   108  		next uint32
   109  	}{
   110  		{
   111  			name: "Successful compare-and-swap with prev == new",
   112  			prev: 10,
   113  			old:  10,
   114  			new:  10,
   115  			next: 10,
   116  		},
   117  		{
   118  			name: "Successful compare-and-swap with prev != new",
   119  			prev: 20,
   120  			old:  20,
   121  			new:  22,
   122  			next: 22,
   123  		},
   124  		{
   125  			name: "Failed compare-and-swap with prev == new",
   126  			prev: 31,
   127  			old:  30,
   128  			new:  31,
   129  			next: 31,
   130  		},
   131  		{
   132  			name: "Failed compare-and-swap with prev != new",
   133  			prev: 41,
   134  			old:  40,
   135  			new:  42,
   136  			next: 41,
   137  		},
   138  	}
   139  	for _, test := range tests {
   140  		val := test.prev
   141  		prev := CompareAndSwapUint32(&val, test.old, test.new)
   142  		if got, want := prev, test.prev; got != want {
   143  			t.Errorf("%s: incorrect returned previous value: got %d, expected %d", test.name, got, want)
   144  		}
   145  		if got, want := val, test.next; got != want {
   146  			t.Errorf("%s: incorrect value stored in val: got %d, expected %d", test.name, got, want)
   147  		}
   148  	}
   149  }
   150  
   151  func TestCompareAndSwapUint64(t *testing.T) {
   152  	tests := []struct {
   153  		name string
   154  		prev uint64
   155  		old  uint64
   156  		new  uint64
   157  		next uint64
   158  	}{
   159  		{
   160  			name: "Successful compare-and-swap with prev == new",
   161  			prev: 0x100000000,
   162  			old:  0x100000000,
   163  			new:  0x100000000,
   164  			next: 0x100000000,
   165  		},
   166  		{
   167  			name: "Successful compare-and-swap with prev != new",
   168  			prev: 0x200000000,
   169  			old:  0x200000000,
   170  			new:  0x200000002,
   171  			next: 0x200000002,
   172  		},
   173  		{
   174  			name: "Failed compare-and-swap with prev == new",
   175  			prev: 0x300000001,
   176  			old:  0x300000000,
   177  			new:  0x300000001,
   178  			next: 0x300000001,
   179  		},
   180  		{
   181  			name: "Failed compare-and-swap with prev != new",
   182  			prev: 0x400000001,
   183  			old:  0x400000000,
   184  			new:  0x400000002,
   185  			next: 0x400000001,
   186  		},
   187  	}
   188  	for _, test := range tests {
   189  		val := test.prev
   190  		prev := CompareAndSwapUint64(&val, test.old, test.new)
   191  		if got, want := prev, test.prev; got != want {
   192  			t.Errorf("%s: incorrect returned previous value: got %d, expected %d", test.name, got, want)
   193  		}
   194  		if got, want := val, test.next; got != want {
   195  			t.Errorf("%s: incorrect value stored in val: got %d, expected %d", test.name, got, want)
   196  		}
   197  	}
   198  }