diff options
Diffstat (limited to 'libgo/go/sync/atomic')
-rw-r--r-- | libgo/go/sync/atomic/atomic.c | 28 | ||||
-rw-r--r-- | libgo/go/sync/atomic/atomic_test.go | 102 | ||||
-rw-r--r-- | libgo/go/sync/atomic/doc.go | 6 |
3 files changed, 136 insertions, 0 deletions
diff --git a/libgo/go/sync/atomic/atomic.c b/libgo/go/sync/atomic/atomic.c index e2d9b242fbd..6660a7d4a91 100644 --- a/libgo/go/sync/atomic/atomic.c +++ b/libgo/go/sync/atomic/atomic.c @@ -95,3 +95,31 @@ AddUintptr (uintptr_t *val, uintptr_t delta) { return __sync_add_and_fetch (val, delta); } + +int32_t LoadInt32 (int32_t *addr) + asm ("libgo_sync.atomic.LoadInt32"); + +int32_t +LoadInt32 (int32_t *addr) +{ + int32_t v; + + v = *addr; + while (! __sync_bool_compare_and_swap (addr, v, v)) + v = *addr; + return v; +} + +uint32_t LoadUint32 (uint32_t *addr) + asm ("libgo_sync.atomic.LoadUint32"); + +uint32_t +LoadUint32 (uint32_t *addr) +{ + uint32_t v; + + v = *addr; + while (! __sync_bool_compare_and_swap (addr, v, v)) + v = *addr; + return v; +} diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go index 119ad0036fd..2229e58d0c7 100644 --- a/libgo/go/sync/atomic/atomic_test.go +++ b/libgo/go/sync/atomic/atomic_test.go @@ -308,6 +308,46 @@ func TestCompareAndSwapUintptr(t *testing.T) { } } +func TestLoadInt32(t *testing.T) { + var x struct { + before int32 + i int32 + after int32 + } + x.before = magic32 + x.after = magic32 + for delta := int32(1); delta+delta > delta; delta += delta { + k := LoadInt32(&x.i) + if k != x.i { + t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) + } + x.i += delta + } + if x.before != magic32 || x.after != magic32 { + t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) + } +} + +func TestLoadUint32(t *testing.T) { + var x struct { + before uint32 + i uint32 + after uint32 + } + x.before = magic32 + x.after = magic32 + for delta := uint32(1); delta+delta > delta; delta += delta { + k := LoadUint32(&x.i) + if k != x.i { + t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) + } + x.i += delta + } + if x.before != magic32 || x.after != magic32 { + t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32) + } +} + // Tests of correct behavior, with contention. // (Is the function atomic?) // @@ -537,3 +577,65 @@ func TestHammer64(t *testing.T) { } } } + +func hammerLoadInt32(t *testing.T, uval *uint32) { + val := (*int32)(unsafe.Pointer(uval)) + for { + v := LoadInt32(val) + vlo := v & ((1 << 16) - 1) + vhi := v >> 16 + if vlo != vhi { + t.Fatalf("LoadInt32: %#x != %#x", vlo, vhi) + } + new := v + 1 + 1<<16 + if vlo == 1e4 { + new = 0 + } + if CompareAndSwapInt32(val, v, new) { + break + } + } +} + +func hammerLoadUint32(t *testing.T, val *uint32) { + for { + v := LoadUint32(val) + vlo := v & ((1 << 16) - 1) + vhi := v >> 16 + if vlo != vhi { + t.Fatalf("LoadUint32: %#x != %#x", vlo, vhi) + } + new := v + 1 + 1<<16 + if vlo == 1e4 { + new = 0 + } + if CompareAndSwapUint32(val, v, new) { + break + } + } +} + +func TestHammerLoad(t *testing.T) { + tests := [...]func(*testing.T, *uint32){hammerLoadInt32, hammerLoadUint32} + n := 100000 + if testing.Short() { + n = 10000 + } + const procs = 8 + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs)) + for _, tt := range tests { + c := make(chan int) + var val uint32 + for p := 0; p < procs; p++ { + go func() { + for i := 0; i < n; i++ { + tt(t, &val) + } + c <- 1 + }() + } + for p := 0; p < procs; p++ { + <-c + } + } +} diff --git a/libgo/go/sync/atomic/doc.go b/libgo/go/sync/atomic/doc.go index ec5a0d33af1..b35eb539c05 100644 --- a/libgo/go/sync/atomic/doc.go +++ b/libgo/go/sync/atomic/doc.go @@ -56,6 +56,12 @@ func AddUint64(val *uint64, delta uint64) (new uint64) // AddUintptr atomically adds delta to *val and returns the new value. func AddUintptr(val *uintptr, delta uintptr) (new uintptr) +// LoadInt32 atomically loads *addr. +func LoadInt32(addr *int32) (val int32) + +// LoadUint32 atomically loads *addr. +func LoadUint32(addr *uint32) (val uint32) + // Helper for ARM. Linker will discard on other systems func panic64() { panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)") |