github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/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 StorepNoWB(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 if uintptr(unsafe.Pointer(addr))&7 != 0 { 110 *(*int)(nil) = 0 // crash on unaligned uint64 111 } 112 _ = *addr // if nil, fault before taking the lock 113 var ok bool 114 addrLock(addr).lock() 115 if *addr == old { 116 *addr = new 117 ok = true 118 } 119 addrLock(addr).unlock() 120 return ok 121 } 122 123 //go:nosplit 124 func Xadd64(addr *uint64, delta int64) uint64 { 125 if uintptr(unsafe.Pointer(addr))&7 != 0 { 126 *(*int)(nil) = 0 // crash on unaligned uint64 127 } 128 _ = *addr // if nil, fault before taking the lock 129 var r uint64 130 addrLock(addr).lock() 131 r = *addr + uint64(delta) 132 *addr = r 133 addrLock(addr).unlock() 134 return r 135 } 136 137 //go:nosplit 138 func Xchg64(addr *uint64, v uint64) uint64 { 139 if uintptr(unsafe.Pointer(addr))&7 != 0 { 140 *(*int)(nil) = 0 // crash on unaligned uint64 141 } 142 _ = *addr // if nil, fault before taking the lock 143 var r uint64 144 addrLock(addr).lock() 145 r = *addr 146 *addr = v 147 addrLock(addr).unlock() 148 return r 149 } 150 151 //go:nosplit 152 func Load64(addr *uint64) uint64 { 153 if uintptr(unsafe.Pointer(addr))&7 != 0 { 154 *(*int)(nil) = 0 // crash on unaligned uint64 155 } 156 _ = *addr // if nil, fault before taking the lock 157 var r uint64 158 addrLock(addr).lock() 159 r = *addr 160 addrLock(addr).unlock() 161 return r 162 } 163 164 //go:nosplit 165 func Store64(addr *uint64, v uint64) { 166 if uintptr(unsafe.Pointer(addr))&7 != 0 { 167 *(*int)(nil) = 0 // crash on unaligned uint64 168 } 169 _ = *addr // if nil, fault before taking the lock 170 addrLock(addr).lock() 171 *addr = v 172 addrLock(addr).unlock() 173 } 174 175 //go:nosplit 176 func Or8(addr *uint8, v uint8) { 177 // Align down to 4 bytes and use 32-bit CAS. 178 uaddr := uintptr(unsafe.Pointer(addr)) 179 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 180 word := uint32(v) << ((uaddr & 3) * 8) // little endian 181 for { 182 old := *addr32 183 if Cas(addr32, old, old|word) { 184 return 185 } 186 } 187 } 188 189 //go:nosplit 190 func And8(addr *uint8, v uint8) { 191 // Align down to 4 bytes and use 32-bit CAS. 192 uaddr := uintptr(unsafe.Pointer(addr)) 193 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 194 word := uint32(v) << ((uaddr & 3) * 8) // little endian 195 mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian 196 word |= ^mask 197 for { 198 old := *addr32 199 if Cas(addr32, old, old&word) { 200 return 201 } 202 } 203 } 204 205 //go:nosplit 206 func armcas(ptr *uint32, old, new uint32) bool