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 }