mirror of
https://github.com/golang/go
synced 2024-11-21 23:54:40 -07:00
sync/atomic: add LoadUintptr
R=golang-dev, rsc CC=golang-dev https://golang.org/cl/4985041
This commit is contained in:
parent
60d47101aa
commit
ea23ba3e2d
@ -94,3 +94,9 @@ TEXT ·LoadUint32(SB),7,$0
|
|||||||
MOVL 0(AX), AX
|
MOVL 0(AX), AX
|
||||||
MOVL AX, ret+4(FP)
|
MOVL AX, ret+4(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
TEXT ·LoadUintptr(SB),7,$0
|
||||||
|
JMP ·LoadUint32(SB)
|
||||||
|
|
||||||
|
TEXT ·LoadPointer(SB),7,$0
|
||||||
|
JMP ·LoadUint32(SB)
|
||||||
|
@ -67,3 +67,11 @@ TEXT ·LoadUint32(SB),7,$0
|
|||||||
MOVL AX, ret+8(FP)
|
MOVL AX, ret+8(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
TEXT ·LoadUintptr(SB),7,$0
|
||||||
|
JMP ·LoadPointer(SB)
|
||||||
|
|
||||||
|
TEXT ·LoadPointer(SB),7,$0
|
||||||
|
MOVQ addrptr+0(FP), AX
|
||||||
|
MOVQ 0(AX), AX
|
||||||
|
MOVQ AX, ret+8(FP)
|
||||||
|
RET
|
||||||
|
@ -96,3 +96,9 @@ loadloop1:
|
|||||||
BCC loadloop1
|
BCC loadloop1
|
||||||
MOVW R1, val+4(FP)
|
MOVW R1, val+4(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
TEXT ·LoadUintptr(SB),7,$0
|
||||||
|
B ·LoadUint32(SB)
|
||||||
|
|
||||||
|
TEXT ·LoadPointer(SB),7,$0
|
||||||
|
B ·LoadUint32(SB)
|
||||||
|
@ -348,6 +348,50 @@ func TestLoadUint32(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadUintptr(t *testing.T) {
|
||||||
|
var x struct {
|
||||||
|
before uintptr
|
||||||
|
i uintptr
|
||||||
|
after uintptr
|
||||||
|
}
|
||||||
|
var m uint64 = magic64
|
||||||
|
magicptr := uintptr(m)
|
||||||
|
x.before = magicptr
|
||||||
|
x.after = magicptr
|
||||||
|
for delta := uintptr(1); delta+delta > delta; delta += delta {
|
||||||
|
k := LoadUintptr(&x.i)
|
||||||
|
if k != x.i {
|
||||||
|
t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
|
||||||
|
}
|
||||||
|
x.i += delta
|
||||||
|
}
|
||||||
|
if x.before != magicptr || x.after != magicptr {
|
||||||
|
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadPointer(t *testing.T) {
|
||||||
|
var x struct {
|
||||||
|
before uintptr
|
||||||
|
i unsafe.Pointer
|
||||||
|
after uintptr
|
||||||
|
}
|
||||||
|
var m uint64 = magic64
|
||||||
|
magicptr := uintptr(m)
|
||||||
|
x.before = magicptr
|
||||||
|
x.after = magicptr
|
||||||
|
for delta := uintptr(1); delta+delta > delta; delta += delta {
|
||||||
|
k := LoadPointer(&x.i)
|
||||||
|
if k != x.i {
|
||||||
|
t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
|
||||||
|
}
|
||||||
|
x.i = unsafe.Pointer(uintptr(x.i) + delta)
|
||||||
|
}
|
||||||
|
if x.before != magicptr || x.after != magicptr {
|
||||||
|
t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tests of correct behavior, with contention.
|
// Tests of correct behavior, with contention.
|
||||||
// (Is the function atomic?)
|
// (Is the function atomic?)
|
||||||
//
|
//
|
||||||
@ -578,8 +622,8 @@ func TestHammer64(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hammerLoadInt32(t *testing.T, uval *uint32) {
|
func hammerLoadInt32(t *testing.T, valp unsafe.Pointer) {
|
||||||
val := (*int32)(unsafe.Pointer(uval))
|
val := (*int32)(valp)
|
||||||
for {
|
for {
|
||||||
v := LoadInt32(val)
|
v := LoadInt32(val)
|
||||||
vlo := v & ((1 << 16) - 1)
|
vlo := v & ((1 << 16) - 1)
|
||||||
@ -597,7 +641,8 @@ func hammerLoadInt32(t *testing.T, uval *uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hammerLoadUint32(t *testing.T, val *uint32) {
|
func hammerLoadUint32(t *testing.T, valp unsafe.Pointer) {
|
||||||
|
val := (*uint32)(valp)
|
||||||
for {
|
for {
|
||||||
v := LoadUint32(val)
|
v := LoadUint32(val)
|
||||||
vlo := v & ((1 << 16) - 1)
|
vlo := v & ((1 << 16) - 1)
|
||||||
@ -615,8 +660,40 @@ func hammerLoadUint32(t *testing.T, val *uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hammerLoadUintptr(t *testing.T, valp unsafe.Pointer) {
|
||||||
|
val := (*uintptr)(valp)
|
||||||
|
var test64 uint64 = 1 << 50
|
||||||
|
arch32 := uintptr(test64) == 0
|
||||||
|
for {
|
||||||
|
v := LoadUintptr(val)
|
||||||
|
new := v
|
||||||
|
if arch32 {
|
||||||
|
vlo := v & ((1 << 16) - 1)
|
||||||
|
vhi := v >> 16
|
||||||
|
if vlo != vhi {
|
||||||
|
t.Fatalf("LoadUintptr: %#x != %#x", vlo, vhi)
|
||||||
|
}
|
||||||
|
new = v + 1 + 1<<16
|
||||||
|
if vlo == 1e4 {
|
||||||
|
new = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vlo := v & ((1 << 32) - 1)
|
||||||
|
vhi := v >> 32
|
||||||
|
if vlo != vhi {
|
||||||
|
t.Fatalf("LoadUintptr: %#x != %#x", vlo, vhi)
|
||||||
|
}
|
||||||
|
inc := uint64(1 + 1<<32)
|
||||||
|
new = v + uintptr(inc)
|
||||||
|
}
|
||||||
|
if CompareAndSwapUintptr(val, v, new) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHammerLoad(t *testing.T) {
|
func TestHammerLoad(t *testing.T) {
|
||||||
tests := [...]func(*testing.T, *uint32){hammerLoadInt32, hammerLoadUint32}
|
tests := [...]func(*testing.T, unsafe.Pointer){hammerLoadInt32, hammerLoadUint32, hammerLoadUintptr}
|
||||||
n := 100000
|
n := 100000
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
n = 10000
|
n = 10000
|
||||||
@ -625,11 +702,11 @@ func TestHammerLoad(t *testing.T) {
|
|||||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
|
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
c := make(chan int)
|
c := make(chan int)
|
||||||
var val uint32
|
var val uint64
|
||||||
for p := 0; p < procs; p++ {
|
for p := 0; p < procs; p++ {
|
||||||
go func() {
|
go func() {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
tt(t, &val)
|
tt(t, unsafe.Pointer(&val))
|
||||||
}
|
}
|
||||||
c <- 1
|
c <- 1
|
||||||
}()
|
}()
|
||||||
|
@ -22,6 +22,10 @@
|
|||||||
//
|
//
|
||||||
package atomic
|
package atomic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// BUG(rsc): On ARM, the 64-bit functions use instructions unavailable before ARM 11.
|
// BUG(rsc): On ARM, the 64-bit functions use instructions unavailable before ARM 11.
|
||||||
//
|
//
|
||||||
// On x86-32, the 64-bit functions use instructions unavailable before the Pentium.
|
// On x86-32, the 64-bit functions use instructions unavailable before the Pentium.
|
||||||
@ -62,6 +66,12 @@ func LoadInt32(addr *int32) (val int32)
|
|||||||
// LoadUint32 atomically loads *addr.
|
// LoadUint32 atomically loads *addr.
|
||||||
func LoadUint32(addr *uint32) (val uint32)
|
func LoadUint32(addr *uint32) (val uint32)
|
||||||
|
|
||||||
|
// LoadUintptr atomically loads *addr.
|
||||||
|
func LoadUintptr(addr *uintptr) (val uintptr)
|
||||||
|
|
||||||
|
// LoadPointer atomically loads *addr.
|
||||||
|
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
|
||||||
|
|
||||||
// Helper for ARM. Linker will discard on other systems
|
// Helper for ARM. Linker will discard on other systems
|
||||||
func panic64() {
|
func panic64() {
|
||||||
panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
|
panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
|
||||||
|
Loading…
Reference in New Issue
Block a user