summaryrefslogtreecommitdiff
path: root/libgo/go/sync/atomic
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/sync/atomic')
-rw-r--r--libgo/go/sync/atomic/atomic.c28
-rw-r--r--libgo/go/sync/atomic/atomic_test.go102
-rw-r--r--libgo/go/sync/atomic/doc.go6
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)")