github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 //go:build arm 6 7 package atomic 8 9 import ( 10 "internal/cpu" 11 "unsafe" 12 ) 13 14 // Export some functions via linkname to assembly in sync/atomic. 15 // 16 //go:linkname Xchg 17 //go:linkname Xchguintptr 18 19 type spinlock struct { 20 v uint32 21 } 22 23 //go:nosplit 24 func (l *spinlock) lock() { 25 for { 26 if Cas(&l.v, 0, 1) { 27 return 28 } 29 } 30 } 31 32 //go:nosplit 33 func (l *spinlock) unlock() { 34 Store(&l.v, 0) 35 } 36 37 var locktab [57]struct { 38 l spinlock 39 pad [cpu.CacheLinePadSize - unsafe.Sizeof(spinlock{})]byte 40 } 41 42 func addrLock(addr *uint64) *spinlock { 43 return &locktab[(uintptr(unsafe.Pointer(addr))>>3)%uintptr(len(locktab))].l 44 } 45 46 // Atomic add and return new value. 47 // 48 //go:nosplit 49 func Xadd(val *uint32, delta int32) uint32 { 50 for { 51 oval := *val 52 nval := oval + uint32(delta) 53 if Cas(val, oval, nval) { 54 return nval 55 } 56 } 57 } 58 59 //go:noescape 60 func Xadduintptr(ptr *uintptr, delta uintptr) uintptr 61 62 //go:nosplit 63 func Xchg(addr *uint32, v uint32) uint32 { 64 for { 65 old := *addr 66 if Cas(addr, old, v) { 67 return old 68 } 69 } 70 } 71 72 //go:nosplit 73 func Xchguintptr(addr *uintptr, v uintptr) uintptr { 74 return uintptr(Xchg((*uint32)(unsafe.Pointer(addr)), uint32(v))) 75 } 76 77 // Not noescape -- it installs a pointer to addr. 78 func StorepNoWB(addr unsafe.Pointer, v unsafe.Pointer) 79 80 //go:noescape 81 func Store(addr *uint32, v uint32) 82 83 //go:noescape 84 func StoreRel(addr *uint32, v uint32) 85 86 //go:noescape 87 func StoreReluintptr(addr *uintptr, v uintptr) 88 89 //go:nosplit 90 func goCas64(addr *uint64, old, new uint64) bool { 91 if uintptr(unsafe.Pointer(addr))&7 != 0 { 92 *(*int)(nil) = 0 // crash on unaligned uint64 93 } 94 _ = *addr // if nil, fault before taking the lock 95 var ok bool 96 addrLock(addr).lock() 97 if *addr == old { 98 *addr = new 99 ok = true 100 } 101 addrLock(addr).unlock() 102 return ok 103 } 104 105 //go:nosplit 106 func goXadd64(addr *uint64, delta int64) uint64 { 107 if uintptr(unsafe.Pointer(addr))&7 != 0 { 108 *(*int)(nil) = 0 // crash on unaligned uint64 109 } 110 _ = *addr // if nil, fault before taking the lock 111 var r uint64 112 addrLock(addr).lock() 113 r = *addr + uint64(delta) 114 *addr = r 115 addrLock(addr).unlock() 116 return r 117 } 118 119 //go:nosplit 120 func goXchg64(addr *uint64, v uint64) uint64 { 121 if uintptr(unsafe.Pointer(addr))&7 != 0 { 122 *(*int)(nil) = 0 // crash on unaligned uint64 123 } 124 _ = *addr // if nil, fault before taking the lock 125 var r uint64 126 addrLock(addr).lock() 127 r = *addr 128 *addr = v 129 addrLock(addr).unlock() 130 return r 131 } 132 133 //go:nosplit 134 func goLoad64(addr *uint64) uint64 { 135 if uintptr(unsafe.Pointer(addr))&7 != 0 { 136 *(*int)(nil) = 0 // crash on unaligned uint64 137 } 138 _ = *addr // if nil, fault before taking the lock 139 var r uint64 140 addrLock(addr).lock() 141 r = *addr 142 addrLock(addr).unlock() 143 return r 144 } 145 146 //go:nosplit 147 func goStore64(addr *uint64, v uint64) { 148 if uintptr(unsafe.Pointer(addr))&7 != 0 { 149 *(*int)(nil) = 0 // crash on unaligned uint64 150 } 151 _ = *addr // if nil, fault before taking the lock 152 addrLock(addr).lock() 153 *addr = v 154 addrLock(addr).unlock() 155 } 156 157 //go:nosplit 158 func Or8(addr *uint8, v uint8) { 159 // Align down to 4 bytes and use 32-bit CAS. 160 uaddr := uintptr(unsafe.Pointer(addr)) 161 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 162 word := uint32(v) << ((uaddr & 3) * 8) // little endian 163 for { 164 old := *addr32 165 if Cas(addr32, old, old|word) { 166 return 167 } 168 } 169 } 170 171 //go:nosplit 172 func And8(addr *uint8, v uint8) { 173 // Align down to 4 bytes and use 32-bit CAS. 174 uaddr := uintptr(unsafe.Pointer(addr)) 175 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 176 word := uint32(v) << ((uaddr & 3) * 8) // little endian 177 mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian 178 word |= ^mask 179 for { 180 old := *addr32 181 if Cas(addr32, old, old&word) { 182 return 183 } 184 } 185 } 186 187 //go:nosplit 188 func Or(addr *uint32, v uint32) { 189 for { 190 old := *addr 191 if Cas(addr, old, old|v) { 192 return 193 } 194 } 195 } 196 197 //go:nosplit 198 func And(addr *uint32, v uint32) { 199 for { 200 old := *addr 201 if Cas(addr, old, old&v) { 202 return 203 } 204 } 205 } 206 207 //go:nosplit 208 func armcas(ptr *uint32, old, new uint32) bool 209 210 //go:noescape 211 func Load(addr *uint32) uint32 212 213 // NO go:noescape annotation; *addr escapes if result escapes (#31525) 214 func Loadp(addr unsafe.Pointer) unsafe.Pointer 215 216 //go:noescape 217 func Load8(addr *uint8) uint8 218 219 //go:noescape 220 func LoadAcq(addr *uint32) uint32 221 222 //go:noescape 223 func LoadAcquintptr(ptr *uintptr) uintptr 224 225 //go:noescape 226 func Cas64(addr *uint64, old, new uint64) bool 227 228 //go:noescape 229 func CasRel(addr *uint32, old, new uint32) bool 230 231 //go:noescape 232 func Xadd64(addr *uint64, delta int64) uint64 233 234 //go:noescape 235 func Xchg64(addr *uint64, v uint64) uint64 236 237 //go:noescape 238 func Load64(addr *uint64) uint64 239 240 //go:noescape 241 func Store8(addr *uint8, v uint8) 242 243 //go:noescape 244 func Store64(addr *uint64, v uint64)