github.com/mitghi/x@v0.0.0-20191206171256-71e86edf750d/pointers/pointers_test.go (about)

     1  /* MIT License
     2  *
     3  * Copyright (c) 2018 Mike Taghavi <mitghi[at]gmail.com>
     4  *
     5  * Permission is hereby granted, free of charge, to any person obtaining a copy
     6  * of this software and associated documentation files (the "Software"), to deal
     7  * in the Software without restriction, including without limitation the rights
     8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  * copies of the Software, and to permit persons to whom the Software is
    10  * furnished to do so, subject to the following conditions:
    11  * The above copyright notice and this permission notice shall be included in all
    12  * copies or substantial portions of the Software.
    13  *
    14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20  * SOFTWARE.
    21   */
    22  
    23  package pointers
    24  
    25  import (
    26  	"fmt"
    27  	"testing"
    28  	"unsafe"
    29  )
    30  
    31  type Sample struct {
    32  	value int
    33  }
    34  
    35  type SliceIFTest struct {
    36  	nodes []interface{}
    37  	sid   string
    38  }
    39  
    40  type SliceTest struct {
    41  	nodes []unsafe.Pointer
    42  	sid   string
    43  	rdi   uint64
    44  }
    45  
    46  type ArrayTest struct {
    47  	nodes [16]unsafe.Pointer
    48  	sid   string
    49  }
    50  
    51  type tststore struct {
    52  	counter uint64
    53  	nodes   *SliceTest
    54  }
    55  
    56  type ststaligned struct {
    57  	nodes                  []unsafe.Pointer // storage with capacity `size`, pow2
    58  	wri, rdi, maxrdi, size uint64           // write, read, max-read and size (mask) indexes
    59  	count                  uint64           // occupancy counter
    60  	addrdata               uintptr
    61  }
    62  
    63  // - MARK: Test-structs section.
    64  
    65  type tstsample struct {
    66  	value int
    67  }
    68  
    69  type tstslice struct {
    70  	nodes []unsafe.Pointer
    71  	sid   string
    72  }
    73  
    74  func init() {
    75  	const _archfmt = "========================\n%-6s%8d\n%-6s%12d\n%-6s%11d\n========================\n"
    76  	fmt.Printf(_archfmt,
    77  		"Address size", ArchADDRSIZE,
    78  		"Tag size", ArchMAXTAG,
    79  		"Word size", ArchWORDSIZE)
    80  }
    81  
    82  func TestAtomicArray(t *testing.T) {
    83  	var (
    84  		s    *Sample    = &Sample{value: 8}
    85  		a    *ArrayTest = &ArrayTest{}
    86  		sptr unsafe.Pointer
    87  		sval *Sample
    88  		ok   bool
    89  	)
    90  	if !SetArraySlot(unsafe.Pointer(&a.nodes), 6, ArchPTRSIZE, unsafe.Pointer(s)) {
    91  		t.Fatal("inconsistent state, cannot set slot.")
    92  	}
    93  	fmt.Println(a.nodes)
    94  	sptr, ok = PopArraySlot(unsafe.Pointer(&a.nodes), 6, ArchPTRSIZE)
    95  	if !ok {
    96  		t.Fatal("inconsistent state, cannot pop slot.")
    97  	}
    98  	sval = (*Sample)(sptr)
    99  	if sval == nil {
   100  		t.Fatal("inconsistent state.")
   101  	} else if sval.value != 8 {
   102  		t.Fatal("assertion failed.")
   103  	}
   104  	fmt.Println("Pointer(S) has Value(", sval.value, ")")
   105  	if a.nodes[6] != nil {
   106  		t.Fatal("inconsistent state.")
   107  	}
   108  }
   109  
   110  func TestAtomicSliceWithInterface(t *testing.T) {
   111  	var (
   112  		s    *Sample      = &Sample{value: 8}
   113  		a    *SliceIFTest = &SliceIFTest{nodes: make([]interface{}, 16)}
   114  		sptr unsafe.Pointer
   115  		sval *Sample
   116  		ok   bool
   117  	)
   118  	if !SetSliceSlotI(unsafe.Pointer(&a.nodes), 0, sizeINTERFACE, unsafe.Pointer(s)) {
   119  		t.Fatal("inconsistent state, cannot set slot.")
   120  	}
   121  	if a.nodes[0] == nil {
   122  		t.Fatal("inconsistent state, value is not inserted.")
   123  	} else {
   124  		fmt.Println(a.nodes[2], " is the head value", a.nodes[1])
   125  	}
   126  	fmt.Println("nodes(iface):", a.nodes)
   127  	sptr, ok = PopSliceSlot(unsafe.Pointer(&a.nodes), 0, sizeINTERFACE)
   128  	if !ok {
   129  		t.Fatal("inconsistent state, cannot pop slot.")
   130  	}
   131  	sval = *(**Sample)(sptr)
   132  	if sval == nil {
   133  		t.Fatal("inconsistent state.")
   134  	} else if sval.value != 8 {
   135  		t.Fatal("assertion failed.")
   136  	}
   137  	fmt.Println("Pointer(S) has Value(", sval.value, ")")
   138  }
   139  
   140  func TestAtomicSlice(t *testing.T) {
   141  	var (
   142  		s    *Sample    = &Sample{value: 8}
   143  		a    *SliceTest = &SliceTest{nodes: make([]unsafe.Pointer, 16)}
   144  		sptr unsafe.Pointer
   145  		sval *Sample
   146  		ok   bool
   147  	)
   148  	if !SetSliceSlot(unsafe.Pointer(&a.nodes), 0, ArchPTRSIZE, unsafe.Pointer(s)) {
   149  		t.Fatal("inconsistent state, cannot set slot.")
   150  	}
   151  	if a.nodes[0] == nil {
   152  		t.Fatal("inconsistent state, value is not inserted.")
   153  	}
   154  	fmt.Printf("nodes: %#x\n", a.nodes)
   155  	sptr, ok = PopSliceSlot(unsafe.Pointer(&a.nodes), 0, ArchPTRSIZE)
   156  	if !ok {
   157  		t.Fatal("inconsistent state, cannot pop slot.")
   158  	}
   159  	fmt.Printf("nodes: %#x\n", a.nodes)
   160  	sval = (*Sample)(sptr)
   161  	if sval == nil {
   162  		t.Fatal("inconsistent state.")
   163  	} else if sval.value != 8 {
   164  		t.Fatal("assertion failed.")
   165  	}
   166  	fmt.Println("Pointer(S) has Value(", sval.value, ")")
   167  }
   168  
   169  func TestCASTag(t *testing.T) {
   170  	var (
   171  		s    *Sample = &Sample{value: 8}
   172  		sptr unsafe.Pointer
   173  		ok   bool
   174  		err  error
   175  	)
   176  	sptr, err = TaggedPointer(unsafe.Pointer(s), 1)
   177  	if err != nil {
   178  		t.Fatal("inconsistent state, expected err==nil.")
   179  	}
   180  	fmt.Println("sptr: ", sptr)
   181  	if sptr, ok = CompareAndSwapPointerTag(sptr, 1, 2); sptr == nil || !ok {
   182  		t.Fatal("inconsistent state, expected !nil, true.", sptr, ok)
   183  	}
   184  	fmt.Println("sptr: swap1->2 ", sptr)
   185  	if tag := GetTag(sptr); tag != 2 {
   186  		t.Fatal("assertion failed, expected 2. got ", tag)
   187  	}
   188  }
   189  
   190  func TestRDCSS(t *testing.T) {
   191  	var (
   192  		expected = &tststore{
   193  			counter: 16,
   194  			nodes:   &SliceTest{make([]unsafe.Pointer, 0), "replaced", 0},
   195  		}
   196  		c = &tststore{
   197  			counter: 16,
   198  			nodes:   &SliceTest{make([]unsafe.Pointer, 0), "original", 0},
   199  		}
   200  		crdiptr unsafe.Pointer
   201  	)
   202  	crdiptr = unsafe.Pointer(&c.counter)
   203  	if !RDCSS(
   204  		(*unsafe.Pointer)(crdiptr),
   205  		(unsafe.Pointer)(unsafe.Pointer(uintptr(expected.counter))),
   206  		(*unsafe.Pointer)(unsafe.Pointer(&c.nodes)),
   207  		unsafe.Pointer(c.nodes),
   208  		unsafe.Pointer(expected.nodes),
   209  	) {
   210  		t.Fatal("Expected RDCSS to succeed")
   211  	}
   212  	if c.nodes == nil {
   213  		t.Fatal("inconsistent state.")
   214  	}
   215  	if c.nodes.sid != "replaced" {
   216  		t.Fatal("inconsistent state.", c.nodes)
   217  	}
   218  }
   219  
   220  func TestRDCSS2(t *testing.T) {
   221  	var (
   222  		item  = &Sample{16}
   223  		sl    [8]unsafe.Pointer
   224  		slptr *[8]unsafe.Pointer
   225  		n     *Sample
   226  	)
   227  	slptr = &sl
   228  	if !SetArraySlot(unsafe.Pointer(slptr), 4, unsafe.Sizeof(slptr), unsafe.Pointer(item)) {
   229  		t.Fatal("inconsistent state.")
   230  	}
   231  	nsptr, ok := PopArraySlot(unsafe.Pointer(slptr), 4, unsafe.Sizeof(slptr))
   232  	if !ok {
   233  		t.Fatal("inconsistent state.")
   234  	}
   235  	n = (*Sample)(nsptr)
   236  	if n == nil {
   237  		t.Fatal("inconsistent state.")
   238  	} else if n.value != 16 {
   239  		t.Fatal("inconsistent state.")
   240  	}
   241  }
   242  
   243  func TestRDCSS2x(t *testing.T) {
   244  	var (
   245  		s       *tstsample     = &tstsample{value: 64}
   246  		n       *tstsample     = &tstsample{value: 128}
   247  		ring    *ststaligned   = &ststaligned{nodes: make([]unsafe.Pointer, 8)}
   248  		slotptr unsafe.Pointer = unsafe.Pointer(OffsetSliceSlot(unsafe.Pointer(&ring.nodes), 1, ArchPTRSIZE))
   249  		rdiPtr  unsafe.Pointer = unsafe.Pointer(&ring.rdi)
   250  		vptr    **tstsample    // value pointer
   251  	)
   252  	if !SetSliceSlot(unsafe.Pointer(&ring.nodes), 1, ArchPTRSIZE, unsafe.Pointer(&s)) {
   253  		t.Fatal("inconsistent state, can't write to slice/slot.")
   254  	}
   255  	if ring.nodes[1] == nil {
   256  		t.Fatal("assertion failed, expected non-nil.")
   257  	}
   258  	vptr = (**tstsample)(ring.nodes[1])
   259  	if vptr == nil {
   260  		t.Fatal("assertion failed, expected non-nil.")
   261  	} else if *vptr == nil {
   262  		t.Fatal("assertion failed, expected non-nil.")
   263  	}
   264  	if (*vptr) != s {
   265  		t.Fatal("assertion failed, expected equal as 's' is written to slot 1.")
   266  	}
   267  	if (((*vptr).value != s.value) && s.value == 64) || s.value != 64 {
   268  		t.Fatal("assertion failed, invalid pointers.")
   269  	}
   270  	fmt.Printf("nodes: %#x\n", ring.nodes)
   271  	if !RDCSS(
   272  		(*unsafe.Pointer)(unsafe.Pointer(&rdiPtr)),
   273  		(unsafe.Pointer)(unsafe.Pointer(rdiPtr)),
   274  		(*unsafe.Pointer)(unsafe.Pointer(slotptr)),
   275  		(unsafe.Pointer)(unsafe.Pointer(&s)),
   276  		(unsafe.Pointer)(unsafe.Pointer(n)),
   277  	) {
   278  		t.Fatal("inconsistent state, RDCSS failure.")
   279  	}
   280  	if s == nil {
   281  		t.Fatal("assertion failed, fatal condition from incorrect pointer mutation.")
   282  	} else if s.value != 64 {
   283  		t.Fatal("assertion failed, invalid pointer.")
   284  	}
   285  	fmt.Printf("nodes: %#x\n", ring.nodes)
   286  	if ring.nodes[1] == nil {
   287  		t.Fatal("assertion failed, expected non-nil for occupied slot.")
   288  	}
   289  	if s == nil {
   290  		t.Fatal("assertion failed, fatal condition from incorrect pointer mutation.")
   291  	}
   292  	vptr = (**tstsample)(slotptr)
   293  	if vptr == nil {
   294  		t.Fatal("assertion failed, expected non-nil pointer.")
   295  	} else if *vptr == nil {
   296  		t.Fatal("assertion failed, expected non-nil pointer.")
   297  	}
   298  	if (*vptr) != n {
   299  		t.Fatal("assertion failed, expected equal as 's' is swapped with 'n'.")
   300  	}
   301  	if (((*vptr).value != n.value) && n.value == 128) || n.value != 128 {
   302  		t.Fatal("assertion failed, invalid pointers.")
   303  	}
   304  	fmt.Println("slotptr:", *(**tstsample)(slotptr), "addr:", slotptr, &n, ring.nodes, ring.nodes[1])
   305  }