runtime/internal/atomic: new package, API copied from Go 1.7
authorIan Lance Taylor <ian@gcc.gnu.org>
Sat, 10 Sep 2016 12:21:59 +0000 (12:21 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 10 Sep 2016 12:21:59 +0000 (12:21 +0000)
    Copy over the Go 1.7 runtime/internal/atomic package, but implement the
    functions in C using __atomic functions rather than using the
    processor-specific assembler code.

    Reviewed-on: https://go-review.googlesource.com/29010

From-SVN: r240070

gcc/go/gofrontend/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/go/runtime/internal/atomic/atomic.c [new file with mode: 0644]
libgo/go/runtime/internal/atomic/atomic_test.go [new file with mode: 0644]
libgo/go/runtime/internal/atomic/gccgo.go [new file with mode: 0644]
libgo/go/runtime/internal/atomic/stubs.go [new file with mode: 0644]

index daa4bcf8bc6213823a3ebfc670c0f72af402aa7f..487adbe8e50315aa933e98cf8f1142a88c76684b 100644 (file)
@@ -1,4 +1,4 @@
-6e791d2f3c183d55fdcabe3df20f01c029fd6d54
+04fe765560107e5d4c5f98c1022765930a1069f9
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 0a54a8972c5bcdeab201c4555ba3073ffd6fb2c5..1fde5086812e440ebc904153955a6a19a5009547 100644 (file)
@@ -843,6 +843,8 @@ libgo_go_objs = \
        net/rpc/jsonrpc.lo \
        runtime/debug.lo \
        runtime/pprof.lo \
+       runtime/internal/atomic.lo \
+       runtime/internal/atomic_c.lo \
        sync/atomic.lo \
        sync/atomic_c.lo \
        text/scanner.lo \
@@ -2365,6 +2367,18 @@ runtime/pprof/check: $(CHECK_DEPS)
 # Also use -fno-inline to get better results from the memory profiler.
 runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
 
+@go_include@ runtime/internal/atomic.lo.dep
+runtime/internal/atomic.lo.dep: $(srcdir)/go/runtime/internal/atomic/*.go
+       $(BUILDDEPS)
+runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime/internal/atomic.lo:
+       $(BUILDPACKAGE)
+runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc runtime/internal/atomic.lo
+       $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
+runtime/internal/atomic/check: $(CHECK_DEPS)
+       @$(CHECK)
+.PHONY: runtime/internal/atomic/check
+
 @go_include@ sync/atomic.lo.dep
 sync/atomic.lo.dep: $(srcdir)/go/sync/atomic/*.go
        $(BUILDDEPS)
@@ -2800,6 +2814,8 @@ runtime/debug.gox: runtime/debug.lo
        $(BUILDGOX)
 runtime/pprof.gox: runtime/pprof.lo
        $(BUILDGOX)
+runtime/internal/atomic.gox: runtime/internal/atomic.lo
+       $(BUILDGOX)
 
 sync/atomic.gox: sync/atomic.lo
        $(BUILDGOX)
@@ -2954,6 +2970,7 @@ TEST_PACKAGES = \
        path/filepath/check \
        regexp/syntax/check \
        runtime/pprof/check \
+       runtime/internal/atomic/check \
        sync/atomic/check \
        text/scanner/check \
        text/tabwriter/check \
index d9c510028b681cf5ca11896b390f699dc56a7ca2..931a6c9e0caef2a7af529c107c262e79f8ae392f 100644 (file)
@@ -212,6 +212,7 @@ am__DEPENDENCIES_1 = bufio.lo bytes.lo bytes/index.lo context.lo \
        old/regexp.lo old/template.lo os/exec.lo os/signal.lo \
        os/user.lo path/filepath.lo regexp/syntax.lo \
        net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
+       runtime/internal/atomic.lo runtime/internal/atomic_c.lo \
        sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
        text/tabwriter.lo text/template.lo text/template/parse.lo \
        testing/iotest.lo testing/quick.lo unicode/utf16.lo \
@@ -1096,6 +1097,8 @@ libgo_go_objs = \
        net/rpc/jsonrpc.lo \
        runtime/debug.lo \
        runtime/pprof.lo \
+       runtime/internal/atomic.lo \
+       runtime/internal/atomic_c.lo \
        sync/atomic.lo \
        sync/atomic_c.lo \
        text/scanner.lo \
@@ -1247,6 +1250,7 @@ runtime_go_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
 # otherwise we can't get the line numbers.
 # Also use -fno-inline to get better results from the memory profiler.
 runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
+runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
 
 # How to build a .gox file from a .lo file.
 BUILDGOX = \
@@ -1384,6 +1388,7 @@ TEST_PACKAGES = \
        path/filepath/check \
        regexp/syntax/check \
        runtime/pprof/check \
+       runtime/internal/atomic/check \
        sync/atomic/check \
        text/scanner/check \
        text/tabwriter/check \
@@ -4987,6 +4992,17 @@ runtime/pprof/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: runtime/pprof/check
 
+@go_include@ runtime/internal/atomic.lo.dep
+runtime/internal/atomic.lo.dep: $(srcdir)/go/runtime/internal/atomic/*.go
+       $(BUILDDEPS)
+runtime/internal/atomic.lo:
+       $(BUILDPACKAGE)
+runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc runtime/internal/atomic.lo
+       $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
+runtime/internal/atomic/check: $(CHECK_DEPS)
+       @$(CHECK)
+.PHONY: runtime/internal/atomic/check
+
 @go_include@ sync/atomic.lo.dep
 sync/atomic.lo.dep: $(srcdir)/go/sync/atomic/*.go
        $(BUILDDEPS)
@@ -5415,6 +5431,8 @@ runtime/debug.gox: runtime/debug.lo
        $(BUILDGOX)
 runtime/pprof.gox: runtime/pprof.lo
        $(BUILDGOX)
+runtime/internal/atomic.gox: runtime/internal/atomic.lo
+       $(BUILDGOX)
 
 sync/atomic.gox: sync/atomic.lo
        $(BUILDGOX)
diff --git a/libgo/go/runtime/internal/atomic/atomic.c b/libgo/go/runtime/internal/atomic/atomic.c
new file mode 100644 (file)
index 0000000..3393fbe
--- /dev/null
@@ -0,0 +1,237 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "runtime.h"
+
+uint32_t Load (uint32_t *ptr)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Load")
+  __attribute__ ((no_split_stack));
+
+uint32_t
+Load (uint32_t *ptr)
+{
+  return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+void *Loadp (void *ptr)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loadp")
+  __attribute__ ((no_split_stack));
+
+void *
+Loadp (void *ptr)
+{
+  return __atomic_load_n ((void **) ptr, __ATOMIC_ACQUIRE);
+}
+
+uint64_t Load64 (uint64_t *ptr)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Load64")
+  __attribute__ ((no_split_stack));
+
+uint64_t
+Load64 (uint64_t *ptr)
+{
+  return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+uintptr_t Loaduintptr (uintptr_t *ptr)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loaduintptr")
+  __attribute__ ((no_split_stack));
+
+uintptr_t
+Loaduintptr (uintptr_t *ptr)
+{
+  return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+uintgo Loaduint (uintgo *ptr)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loaduint")
+  __attribute__ ((no_split_stack));
+
+uintgo
+Loaduint (uintgo *ptr)
+{
+  return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+int64_t Loadint64 (int64_t *ptr)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loadint64")
+  __attribute__ ((no_split_stack));
+
+int64_t
+Loadint64 (int64_t *ptr)
+{
+  return __atomic_load_n (ptr, __ATOMIC_ACQUIRE);
+}
+
+uint32_t Xadd (uint32_t *ptr, int32_t delta)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadd")
+  __attribute__ ((no_split_stack));
+
+uint32_t
+Xadd (uint32_t *ptr, int32_t delta)
+{
+  return __atomic_add_fetch (ptr, (uint32_t) delta, __ATOMIC_SEQ_CST);
+}
+
+uint64_t Xadd64 (uint64_t *ptr, int64_t delta)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadd64")
+  __attribute__ ((no_split_stack));
+
+uint64_t
+Xadd64 (uint64_t *ptr, int64_t delta)
+{
+  return __atomic_add_fetch (ptr, (uint64_t) delta, __ATOMIC_SEQ_CST);
+}
+
+uintptr_t Xadduintptr (uintptr_t *ptr, uintptr_t delta)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadduintptr")
+  __attribute__ ((no_split_stack));
+
+uintptr_t
+Xadduintptr (uintptr_t *ptr, uintptr_t delta)
+{
+  return __atomic_add_fetch (ptr, delta, __ATOMIC_SEQ_CST);
+}
+
+int64_t Xaddint64 (int64_t *ptr, int64_t delta)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xaddint64")
+  __attribute__ ((no_split_stack));
+
+int64_t
+Xaddint64 (int64_t *ptr, int64_t delta)
+{
+  return __atomic_add_fetch (ptr, delta, __ATOMIC_SEQ_CST);
+}
+
+uint32_t Xchg (uint32_t *ptr, uint32_t new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchg")
+  __attribute__ ((no_split_stack));
+
+uint32_t
+Xchg (uint32_t *ptr, uint32_t new)
+{
+  return __atomic_exchange_n (ptr, new, __ATOMIC_SEQ_CST);
+}
+
+uint64_t Xchg64 (uint64_t *ptr, uint64_t new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchg64")
+  __attribute__ ((no_split_stack));
+
+uint64_t
+Xchg64 (uint64_t *ptr, uint64_t new)
+{
+  return __atomic_exchange_n (ptr, new, __ATOMIC_SEQ_CST);
+}
+
+uintptr_t Xchguintptr (uintptr_t *ptr, uintptr_t new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchguintptr")
+  __attribute__ ((no_split_stack));
+
+uintptr_t
+Xchguintptr (uintptr_t *ptr, uintptr_t new)
+{
+  return __atomic_exchange_n (ptr, new, __ATOMIC_SEQ_CST);
+}
+
+void And8 (uint8_t *ptr, uint8_t val)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.And8")
+  __attribute__ ((no_split_stack));
+
+void
+And8 (uint8_t *ptr, uint8_t val)
+{
+  __atomic_and_fetch (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void Or8 (uint8_t *ptr, uint8_t val)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Or8")
+  __attribute__ ((no_split_stack));
+
+void
+Or8 (uint8_t *ptr, uint8_t val)
+{
+  __atomic_or_fetch (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+_Bool Cas (uint32_t *ptr, uint32_t old, uint32_t new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Cas")
+  __attribute__ ((no_split_stack));
+
+_Bool
+Cas (uint32_t *ptr, uint32_t old, uint32_t new)
+{
+  return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+_Bool Cas64 (uint64_t *ptr, uint64_t old, uint64_t new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Cas64")
+  __attribute__ ((no_split_stack));
+
+_Bool
+Cas64 (uint64_t *ptr, uint64_t old, uint64_t new)
+{
+  return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+_Bool Casp1 (void **ptr, void *old, void *new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Casp1")
+  __attribute__ ((no_split_stack));
+
+_Bool
+Casp1 (void **ptr, void *old, void *new)
+{
+  return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+_Bool Casuintptr (uintptr_t *ptr, uintptr_t old, uintptr_t new)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Casuintptr")
+  __attribute__ ((no_split_stack));
+
+_Bool
+Casuintptr (uintptr_t *ptr, uintptr_t old, uintptr_t new)
+{
+  return __atomic_compare_exchange_n (ptr, &old, new, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+void Store (uint32_t *ptr, uint32_t val)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Store")
+  __attribute__ ((no_split_stack));
+
+void
+Store (uint32_t *ptr, uint32_t val)
+{
+  __atomic_store_n (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void Store64 (uint64_t *ptr, uint64_t val)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Store64")
+  __attribute__ ((no_split_stack));
+
+void
+Store64 (uint64_t *ptr, uint64_t val)
+{
+  __atomic_store_n (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void Storeuintptr (uintptr_t *ptr, uintptr_t val)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Storeuintptr")
+  __attribute__ ((no_split_stack));
+
+void
+Storeuintptr (uintptr_t *ptr, uintptr_t val)
+{
+  __atomic_store_n (ptr, val, __ATOMIC_SEQ_CST);
+}
+
+void StorepNoWB (void *ptr, void *val)
+  __asm__ (GOSYM_PREFIX "runtime_internal_atomic.StorepNoWB")
+  __attribute__ ((no_split_stack));
+
+void
+StorepNoWB (void *ptr, void *val)
+{
+  __atomic_store_n ((void**) ptr, val, __ATOMIC_SEQ_CST);
+}
diff --git a/libgo/go/runtime/internal/atomic/atomic_test.go b/libgo/go/runtime/internal/atomic/atomic_test.go
new file mode 100644 (file)
index 0000000..d5dc552
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic_test
+
+import (
+       "runtime"
+       "runtime/internal/atomic"
+       "testing"
+       "unsafe"
+)
+
+func runParallel(N, iter int, f func()) {
+       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(int(N)))
+       done := make(chan bool)
+       for i := 0; i < N; i++ {
+               go func() {
+                       for j := 0; j < iter; j++ {
+                               f()
+                       }
+                       done <- true
+               }()
+       }
+       for i := 0; i < N; i++ {
+               <-done
+       }
+}
+
+func TestXadduintptr(t *testing.T) {
+       const N = 20
+       const iter = 100000
+       inc := uintptr(100)
+       total := uintptr(0)
+       runParallel(N, iter, func() {
+               atomic.Xadduintptr(&total, inc)
+       })
+       if want := uintptr(N * iter * inc); want != total {
+               t.Fatalf("xadduintpr error, want %d, got %d", want, total)
+       }
+       total = 0
+       runParallel(N, iter, func() {
+               atomic.Xadduintptr(&total, inc)
+               atomic.Xadduintptr(&total, uintptr(-int64(inc)))
+       })
+       if total != 0 {
+               t.Fatalf("xadduintpr total error, want %d, got %d", 0, total)
+       }
+}
+
+// Tests that xadduintptr correctly updates 64-bit values. The place where
+// we actually do so is mstats.go, functions mSysStat{Inc,Dec}.
+func TestXadduintptrOnUint64(t *testing.T) {
+       /*      if runtime.BigEndian != 0 {
+               // On big endian architectures, we never use xadduintptr to update
+               // 64-bit values and hence we skip the test.  (Note that functions
+               // mSysStat{Inc,Dec} in mstats.go have explicit checks for
+               // big-endianness.)
+               return
+       }*/
+       const inc = 100
+       val := uint64(0)
+       atomic.Xadduintptr((*uintptr)(unsafe.Pointer(&val)), inc)
+       if inc != val {
+               t.Fatalf("xadduintptr should increase lower-order bits, want %d, got %d", inc, val)
+       }
+}
diff --git a/libgo/go/runtime/internal/atomic/gccgo.go b/libgo/go/runtime/internal/atomic/gccgo.go
new file mode 100644 (file)
index 0000000..6967364
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic
+
+// Stubs for atomic functions that in gccgo are implemented in C.
+
+import "unsafe"
+
+//go:noescape
+func Load(ptr *uint32) uint32
+
+//go:noescape
+func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func Load64(ptr *uint64) uint64
+
+//go:noescape
+func Xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func Xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:noescape
+func Xchg(ptr *uint32, new uint32) uint32
+
+//go:noescape
+func Xchg64(ptr *uint64, new uint64) uint64
+
+//go:noescape
+func Xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func And8(ptr *uint8, val uint8)
+
+//go:noescape
+func Or8(ptr *uint8, val uint8)
+
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
+//go:noescape
+func Cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func Store(ptr *uint32, val uint32)
+
+//go:noescape
+func Store64(ptr *uint64, val uint64)
+
+// StorepNoWB performs *ptr = val atomically and without a write
+// barrier.
+//
+// NO go:noescape annotation; see atomic_pointer.go.
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/libgo/go/runtime/internal/atomic/stubs.go b/libgo/go/runtime/internal/atomic/stubs.go
new file mode 100644 (file)
index 0000000..497b980
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic
+
+import "unsafe"
+
+//go:noescape
+func Cas(ptr *uint32, old, new uint32) bool
+
+// NO go:noescape annotation; see atomic_pointer.go.
+func Casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+
+//go:noescape
+func Casuintptr(ptr *uintptr, old, new uintptr) bool
+
+//go:noescape
+func Storeuintptr(ptr *uintptr, new uintptr)
+
+//go:noescape
+func Loaduintptr(ptr *uintptr) uintptr
+
+//go:noescape
+func Loaduint(ptr *uint) uint
+
+// TODO(matloob): Should these functions have the go:noescape annotation?
+
+//go:noescape
+func Loadint64(ptr *int64) int64
+
+//go:noescape
+func Xaddint64(ptr *int64, delta int64) int64