github.com/aloncn/graphics-go@v0.0.1/src/runtime/internal/atomic/atomic_arm.go (about) 1 // Copyright 2009 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 // +build arm 6 7 package atomic 8 9 import ( 10 "runtime/internal/sys" 11 "unsafe" 12 ) 13 14 type spinlock struct { 15 v uint32 16 } 17 18 //go:nosplit 19 func (l *spinlock) lock() { 20 for { 21 if Cas(&l.v, 0, 1) { 22 return 23 } 24 } 25 } 26 27 //go:nosplit 28 func (l *spinlock) unlock() { 29 Store(&l.v, 0) 30 } 31 32 var locktab [57]struct { 33 l spinlock 34 pad [sys.CacheLineSize - unsafe.Sizeof(spinlock{})]byte 35 } 36 37 func addrLock(addr *uint64) *spinlock { 38 return &locktab[(uintptr(unsafe.Pointer(addr))>>3)%uintptr(len(locktab))].l 39 } 40 41 // Atomic add and return new value. 42 //go:nosplit 43 func Xadd(val *uint32, delta int32) uint32 { 44 for { 45 oval := *val 46 nval := oval + uint32(delta) 47 if Cas(val, oval, nval) { 48 return nval 49 } 50 } 51 } 52 53 //go:noescape 54 func Xadduintptr(ptr *uintptr, delta uintptr) uintptr 55 56 //go:nosplit 57 func Xchg(addr *uint32, v uint32) uint32 { 58 for { 59 old := *addr 60 if Cas(addr, old, v) { 61 return old 62 } 63 } 64 } 65 66 //go:nosplit 67 func Xchguintptr(addr *uintptr, v uintptr) uintptr { 68 return uintptr(Xchg((*uint32)(unsafe.Pointer(addr)), uint32(v))) 69 } 70 71 //go:nosplit 72 func Load(addr *uint32) uint32 { 73 return Xadd(addr, 0) 74 } 75 76 // Should be a built-in for unsafe.Pointer? 77 //go:nosplit 78 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { 79 return unsafe.Pointer(uintptr(p) + x) 80 } 81 82 //go:nosplit 83 func Loadp(addr unsafe.Pointer) unsafe.Pointer { 84 return unsafe.Pointer(uintptr(Xadd((*uint32)(addr), 0))) 85 } 86 87 //go:nosplit 88 func Storep1(addr unsafe.Pointer, v unsafe.Pointer) { 89 for { 90 old := *(*unsafe.Pointer)(addr) 91 if Casp1((*unsafe.Pointer)(addr), old, v) { 92 return 93 } 94 } 95 } 96 97 //go:nosplit 98 func Store(addr *uint32, v uint32) { 99 for { 100 old := *addr 101 if Cas(addr, old, v) { 102 return 103 } 104 } 105 } 106 107 //go:nosplit 108 func Cas64(addr *uint64, old, new uint64) bool { 109 var ok bool 110 addrLock(addr).lock() 111 if *addr == old { 112 *addr = new 113 ok = true 114 } 115 addrLock(addr).unlock() 116 return ok 117 } 118 119 //go:nosplit 120 func Xadd64(addr *uint64, delta int64) uint64 { 121 var r uint64 122 addrLock(addr).lock() 123 r = *addr + uint64(delta) 124 *addr = r 125 addrLock(addr).unlock() 126 return r 127 } 128 129 //go:nosplit 130 func Xchg64(addr *uint64, v uint64) uint64 { 131 var r uint64 132 addrLock(addr).lock() 133 r = *addr 134 *addr = v 135 addrLock(addr).unlock() 136 return r 137 } 138 139 //go:nosplit 140 func Load64(addr *uint64) uint64 { 141 var r uint64 142 addrLock(addr).lock() 143 r = *addr 144 addrLock(addr).unlock() 145 return r 146 } 147 148 //go:nosplit 149 func Store64(addr *uint64, v uint64) { 150 addrLock(addr).lock() 151 *addr = v 152 addrLock(addr).unlock() 153 } 154 155 //go:nosplit 156 func Or8(addr *uint8, v uint8) { 157 // Align down to 4 bytes and use 32-bit CAS. 158 uaddr := uintptr(unsafe.Pointer(addr)) 159 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 160 word := uint32(v) << ((uaddr & 3) * 8) // little endian 161 for { 162 old := *addr32 163 if Cas(addr32, old, old|word) { 164 return 165 } 166 } 167 } 168 169 //go:nosplit 170 func And8(addr *uint8, v uint8) { 171 // Align down to 4 bytes and use 32-bit CAS. 172 uaddr := uintptr(unsafe.Pointer(addr)) 173 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 174 word := uint32(v) << ((uaddr & 3) * 8) // little endian 175 mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian 176 word |= ^mask 177 for { 178 old := *addr32 179 if Cas(addr32, old, old&word) { 180 return 181 } 182 } 183 }