github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/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:nosplit 31 func xchg(addr *uint32, v uint32) uint32 { 32 for { 33 old := *addr 34 if cas(addr, old, v) { 35 return old 36 } 37 } 38 } 39 40 //go:nosplit 41 func xchgp(addr *unsafe.Pointer, v unsafe.Pointer) unsafe.Pointer { 42 for { 43 old := *addr 44 if casp(addr, old, v) { 45 return old 46 } 47 } 48 } 49 50 //go:nosplit 51 func xchguintptr(addr *uintptr, v uintptr) uintptr { 52 return uintptr(xchg((*uint32)(unsafe.Pointer(addr)), uint32(v))) 53 } 54 55 //go:nosplit 56 func atomicload(addr *uint32) uint32 { 57 return xadd(addr, 0) 58 } 59 60 //go:nosplit 61 func atomicloadp(addr unsafe.Pointer) unsafe.Pointer { 62 return unsafe.Pointer(uintptr(xadd((*uint32)(addr), 0))) 63 } 64 65 //go:nosplit 66 func atomicstorep(addr unsafe.Pointer, v unsafe.Pointer) { 67 for { 68 old := *(*unsafe.Pointer)(addr) 69 if casp((*unsafe.Pointer)(addr), old, v) { 70 return 71 } 72 } 73 } 74 75 //go:nosplit 76 func atomicstore(addr *uint32, v uint32) { 77 for { 78 old := *addr 79 if cas(addr, old, v) { 80 return 81 } 82 } 83 } 84 85 //go:nosplit 86 func cas64(addr *uint64, old, new uint64) bool { 87 var ok bool 88 systemstack(func() { 89 lock(addrLock(addr)) 90 if *addr == old { 91 *addr = new 92 ok = true 93 } 94 unlock(addrLock(addr)) 95 }) 96 return ok 97 } 98 99 //go:nosplit 100 func xadd64(addr *uint64, delta int64) uint64 { 101 var r uint64 102 systemstack(func() { 103 lock(addrLock(addr)) 104 r = *addr + uint64(delta) 105 *addr = r 106 unlock(addrLock(addr)) 107 }) 108 return r 109 } 110 111 //go:nosplit 112 func xchg64(addr *uint64, v uint64) uint64 { 113 var r uint64 114 systemstack(func() { 115 lock(addrLock(addr)) 116 r = *addr 117 *addr = v 118 unlock(addrLock(addr)) 119 }) 120 return r 121 } 122 123 //go:nosplit 124 func atomicload64(addr *uint64) uint64 { 125 var r uint64 126 systemstack(func() { 127 lock(addrLock(addr)) 128 r = *addr 129 unlock(addrLock(addr)) 130 }) 131 return r 132 } 133 134 //go:nosplit 135 func atomicstore64(addr *uint64, v uint64) { 136 systemstack(func() { 137 lock(addrLock(addr)) 138 *addr = v 139 unlock(addrLock(addr)) 140 }) 141 } 142 143 //go:nosplit 144 func atomicor8(addr *uint8, v uint8) { 145 // Align down to 4 bytes and use 32-bit CAS. 146 uaddr := uintptr(unsafe.Pointer(addr)) 147 addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3)) 148 word := uint32(v) << ((uaddr & 3) * 8) // little endian 149 for { 150 old := *addr32 151 if cas(addr32, old, old|word) { 152 return 153 } 154 } 155 }