github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/runtime/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 package runtime 6 7 import "unsafe" 8 9 var locktab [57]struct { 10 l mutex 11 pad [_CacheLineSize - unsafe.Sizeof(mutex{})]byte 12 } 13 14 func addrLock(addr *uint64) *mutex { 15 return &locktab[(uintptr(unsafe.Pointer(addr))>>3)%uintptr(len(locktab))].l 16 } 17 18 // Atomic add and return new value. 19 //go:nosplit 20 func xadd(val *uint32, delta int32) uint32 { 21 for { 22 oval := *val 23 nval := oval + uint32(delta) 24 if cas(val, oval, nval) { 25 return nval 26 } 27 } 28 } 29 30 //go:noescape 31 //go:linkname xadduintptr runtime.xadd 32 func xadduintptr(ptr *uintptr, delta uintptr) uintptr 33 34 //go:nosplit 35 func xchg(addr *uint32, v uint32) uint32 { 36 for { 37 old := *addr 38 if cas(addr, old, v) { 39 return old 40 } 41 } 42 } 43 44 //go:nosplit 45 func xchguintptr(addr *uintptr, v uintptr) uintptr { 46 return uintptr(xchg((*uint32)(unsafe.Pointer(addr)), uint32(v))) 47 } 48 49 //go:nosplit 50 func atomicload(addr *uint32) uint32 { 51 return xadd(addr, 0) 52 } 53 54 //go:nosplit 55 func atomicloadp(addr unsafe.Pointer) unsafe.Pointer { 56 return unsafe.Pointer(uintptr(xadd((*uint32)(addr), 0))) 57 } 58 59 //go:nosplit 60 func atomicstorep1(addr unsafe.Pointer, v unsafe.Pointer) { 61 for { 62 old := *(*unsafe.Pointer)(addr) 63 if casp1((*unsafe.Pointer)(addr), old, v) { 64 return 65 } 66 } 67 } 68 69 //go:nosplit 70 func atomicstore(addr *uint32, v uint32) { 71 for { 72 old := *addr 73 if cas(addr, old, v) { 74 return 75 } 76 } 77 } 78 79 //go:nosplit 80 func cas64(addr *uint64, old, new uint64) bool { 81 var ok bool 82 systemstack(func() { 83 lock(addrLock(addr)) 84 if *addr == old { 85 *addr = new 86 ok = true 87 } 88 unlock(addrLock(addr)) 89 }) 90 return ok 91 } 92 93 //go:nosplit 94 func xadd64(addr *uint64, delta int64) uint64 { 95 var r uint64 96 systemstack(func() { 97 lock(addrLock(addr)) 98 r = *addr + uint64(delta) 99 *addr = r 100 unlock(addrLock(addr)) 101 }) 102 return r 103 } 104 105 //go:nosplit 106 func xchg64(addr *uint64, v uint64) uint64 { 107 var r uint64 108 systemstack(func() { 109 lock(addrLock(addr)) 110 r = *addr 111 *addr = v 112 unlock(addrLock(addr)) 113 }) 114 return r 115 } 116 117 //go:nosplit 118 func atomicload64(addr *uint64) uint64 { 119 var r uint64 120 systemstack(func() { 121 lock(addrLock(addr)) 122 r = *addr 123 unlock(addrLock(addr)) 124 }) 125 return r 126 } 127 128 //go:nosplit 129 func atomicstore64(addr *uint64, v uint64) { 130 systemstack(func() { 131 lock(addrLock(addr)) 132 *addr = v 133 unlock(addrLock(addr)) 134 }) 135 } 136 137 //go:nosplit 138 func atomicor8(addr *uint8, v uint8) { 139 // Align down to 4 bytes and use 32-bit CAS. 140 uaddr := uintptr(unsafe.Pointer(addr)) 141 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 142 word := uint32(v) << ((uaddr & 3) * 8) // little endian 143 for { 144 old := *addr32 145 if cas(addr32, old, old|word) { 146 return 147 } 148 } 149 } 150 151 //go:nosplit 152 func atomicand8(addr *uint8, v uint8) { 153 // Align down to 4 bytes and use 32-bit CAS. 154 uaddr := uintptr(unsafe.Pointer(addr)) 155 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 156 word := uint32(v) << ((uaddr & 3) * 8) // little endian 157 mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian 158 word |= ^mask 159 for { 160 old := *addr32 161 if cas(addr32, old, old&word) { 162 return 163 } 164 } 165 }