From e597e0533d69081e6d6b01ca19f2924c1b8307ff Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 21 Oct 2016 20:07:06 +0000 Subject: [PATCH] runtime: copy lfstack code from Go 1.7 runtime Note that lfstack_64bit.go was modified for Solaris support in a different, and better, way than the superseded lfstack.goc code. Reviewed-on: https://go-review.googlesource.com/31673 From-SVN: r241427 --- gcc/go/gofrontend/MERGE | 2 +- libgo/Makefile.am | 1 - libgo/Makefile.in | 6 +- libgo/go/runtime/export_test.go | 14 +++-- libgo/go/runtime/lfstack.go | 50 ++++++++++++++++ libgo/go/runtime/lfstack_32bit.go | 19 +++++++ libgo/go/runtime/lfstack_64bit.go | 8 +-- libgo/runtime/lfstack.goc | 95 ------------------------------- libgo/runtime/runtime.h | 12 +--- 9 files changed, 88 insertions(+), 119 deletions(-) create mode 100644 libgo/go/runtime/lfstack.go create mode 100644 libgo/go/runtime/lfstack_32bit.go delete mode 100644 libgo/runtime/lfstack.goc diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index a331db61b3d..bc954f02cbd 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -14dc8052a09ad0a2226e64ab6b5af69c6923b830 +df6046971233854e5b7533140d4ead095ab69857 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 08947c06b04..1e99810f478 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -488,7 +488,6 @@ runtime_files = \ $(runtime_thread_files) \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - lfstack.c \ malloc.c \ runtime1.c \ sigqueue.c \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 6cbac4278ff..c85ec502236 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -252,8 +252,8 @@ am__objects_5 = go-append.lo go-assert.lo go-breakpoint.lo \ env_posix.lo heapdump.lo mcache.lo mcentral.lo \ $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \ panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \ - thread.lo $(am__objects_2) yield.lo $(am__objects_3) \ - lfstack.lo malloc.lo runtime1.lo sigqueue.lo $(am__objects_4) + thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \ + runtime1.lo sigqueue.lo $(am__objects_4) am_libgo_llgo_la_OBJECTS = $(am__objects_5) libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS) libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -884,7 +884,6 @@ runtime_files = \ $(runtime_thread_files) \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - lfstack.c \ malloc.c \ runtime1.c \ sigqueue.c \ @@ -1562,7 +1561,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heapdump.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfstack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_a-go-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_llgo_a-go-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgolibbegin_a-go-libmain.Po@am__quote@ diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go index 711a551d278..d3443566d92 100644 --- a/libgo/go/runtime/export_test.go +++ b/libgo/go/runtime/export_test.go @@ -6,6 +6,10 @@ package runtime +import ( + "unsafe" +) + //var Fadd64 = fadd64 //var Fsub64 = fsub64 //var Fmul64 = fmul64 @@ -32,11 +36,13 @@ type LFNode struct { Pushcnt uintptr } -func lfstackpush_go(head *uint64, node *LFNode) -func lfstackpop_go(head *uint64) *LFNode +func LFStackPush(head *uint64, node *LFNode) { + lfstackpush(head, (*lfnode)(unsafe.Pointer(node))) +} -var LFStackPush = lfstackpush_go -var LFStackPop = lfstackpop_go +func LFStackPop(head *uint64) *LFNode { + return (*LFNode)(unsafe.Pointer(lfstackpop(head))) +} type ParFor struct { body func(*ParFor, uint32) diff --git a/libgo/go/runtime/lfstack.go b/libgo/go/runtime/lfstack.go new file mode 100644 index 00000000000..2f2958c8869 --- /dev/null +++ b/libgo/go/runtime/lfstack.go @@ -0,0 +1,50 @@ +// Copyright 2012 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. + +// Lock-free stack. +// Initialize head to 0, compare with 0 to test for emptiness. +// The stack does not keep pointers to nodes, +// so they can be garbage collected if there are no other pointers to nodes. +// The following code runs only in non-preemptible contexts. + +package runtime + +import ( + "runtime/internal/atomic" + "unsafe" +) + +// Temporary for C code to call: +//go:linkname lfstackpush runtime.lfstackpush +//go:linkname lfstackpop runtime.lfstackpop + +func lfstackpush(head *uint64, node *lfnode) { + node.pushcnt++ + new := lfstackPack(node, node.pushcnt) + if node1 := lfstackUnpack(new); node1 != node { + print("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n") + throw("lfstackpush") + } + for { + old := atomic.Load64(head) + node.next = old + if atomic.Cas64(head, old, new) { + break + } + } +} + +func lfstackpop(head *uint64) unsafe.Pointer { + for { + old := atomic.Load64(head) + if old == 0 { + return nil + } + node := lfstackUnpack(old) + next := atomic.Load64(&node.next) + if atomic.Cas64(head, old, next) { + return unsafe.Pointer(node) + } + } +} diff --git a/libgo/go/runtime/lfstack_32bit.go b/libgo/go/runtime/lfstack_32bit.go new file mode 100644 index 00000000000..6a992000084 --- /dev/null +++ b/libgo/go/runtime/lfstack_32bit.go @@ -0,0 +1,19 @@ +// Copyright 2014 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. + +// +build 386 arm nacl armbe m68k mips mipsle mips64p32 mips64p32le mipso32 mipsn32 s390 sparc + +package runtime + +import "unsafe" + +// On 32-bit systems, the stored uint64 has a 32-bit pointer and 32-bit count. + +func lfstackPack(node *lfnode, cnt uintptr) uint64 { + return uint64(uintptr(unsafe.Pointer(node)))<<32 | uint64(cnt) +} + +func lfstackUnpack(val uint64) *lfnode { + return (*lfnode)(unsafe.Pointer(uintptr(val >> 32))) +} diff --git a/libgo/go/runtime/lfstack_64bit.go b/libgo/go/runtime/lfstack_64bit.go index 3b0eb986ce3..213efb10706 100644 --- a/libgo/go/runtime/lfstack_64bit.go +++ b/libgo/go/runtime/lfstack_64bit.go @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ignore - -// +build amd64 arm64 mips64 mips64le ppc64 ppc64le s390x +// +build amd64 arm64 mips64 mips64le ppc64 ppc64le s390x arm64be alpha mipsn64 sparc64 package runtime @@ -41,8 +39,8 @@ func lfstackPack(node *lfnode, cnt uintptr) uint64 { } func lfstackUnpack(val uint64) *lfnode { - if GOARCH == "amd64" { - // amd64 systems can place the stack above the VA hole, so we need to sign extend + if GOARCH == "amd64" || GOOS == "solaris" { + // amd64 or Solaris systems can place the stack above the VA hole, so we need to sign extend // val before unpacking. return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3))) } diff --git a/libgo/runtime/lfstack.goc b/libgo/runtime/lfstack.goc deleted file mode 100644 index 5ab1baa436e..00000000000 --- a/libgo/runtime/lfstack.goc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2012 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. - -// Lock-free stack. - -package runtime -#include "runtime.h" -#include "arch.h" - -#if __SIZEOF_POINTER__ == 8 -// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses. -// Use low-order three bits as ABA counter. -// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html -# if defined(__sparc__) || (defined(__sun__) && defined(__amd64__)) -static inline uint64 lfPack(LFNode *node, uintptr cnt) { - return ((uint64)(node)) | ((cnt)&7); -} -static inline LFNode* lfUnpack(uint64 val) { - return (LFNode*)(val&~7); -} -# else -# if defined(__aarch64__) -// Depending on the kernel options, pointers on arm64 can have up to 48 significant -// bits (see https://www.kernel.org/doc/Documentation/arm64/memory.txt). -# define PTR_BITS 48 -# else -// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag. -// So we use 17msb of pointers as ABA counter. -# define PTR_BITS 47 -# endif -# define CNT_BITS (64 - PTR_BITS + 3) -static inline uint64 lfPack(LFNode *node, uintptr cnt) { - return ((uint64)(node)<<(64-PTR_BITS)) | (cnt&(((1<> CNT_BITS) << 3); -} -# endif -#else -static inline uint64 lfPack(LFNode *node, uintptr cnt) { - return ((uint64)(uintptr)(node)<<32) | cnt; -} -static inline LFNode* lfUnpack(uint64 val) { - return (LFNode*)(uintptr)(val >> 32); -} -#endif - -void -runtime_lfstackpush(uint64 *head, LFNode *node) -{ - uint64 old, new; - - if(node != lfUnpack(lfPack(node, 0))) { - runtime_printf("p=%p\n", node); - runtime_throw("runtime_lfstackpush: invalid pointer"); - } - - node->pushcnt++; - new = lfPack(node, node->pushcnt); - for(;;) { - old = runtime_atomicload64(head); - node->next = lfUnpack(old); - if(runtime_cas64(head, old, new)) - break; - } -} - -LFNode* -runtime_lfstackpop(uint64 *head) -{ - LFNode *node, *node2; - uint64 old, new; - - for(;;) { - old = runtime_atomicload64(head); - if(old == 0) - return nil; - node = lfUnpack(old); - node2 = runtime_atomicloadp(&node->next); - new = 0; - if(node2 != nil) - new = lfPack(node2, node2->pushcnt); - if(runtime_cas64(head, old, new)) - return node; - } -} - -func lfstackpush_go(head *uint64, node *LFNode) { - runtime_lfstackpush(head, node); -} - -func lfstackpop_go(head *uint64) (node *LFNode) { - node = runtime_lfstackpop(head); -} diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 8a91429e94a..8be0df4c17d 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -67,7 +67,7 @@ typedef struct FixAlloc FixAlloc; typedef struct hchan Hchan; typedef struct timer Timer; typedef struct gcstats GCStats; -typedef struct LFNode LFNode; +typedef struct lfnode LFNode; typedef struct ParFor ParFor; typedef struct ParForThread ParForThread; typedef struct cgoMal CgoMal; @@ -178,13 +178,6 @@ enum { }; #endif -// Lock-free stack node. -struct LFNode -{ - LFNode *next; - uintptr pushcnt; -}; - // Parallel for descriptor. struct ParFor { @@ -461,7 +454,8 @@ bool runtime_notetsleepg(Note*, int64) // false - timeout */ void runtime_lfstackpush(uint64 *head, LFNode *node) __asm__ (GOSYM_PREFIX "runtime.lfstackpush"); -LFNode* runtime_lfstackpop(uint64 *head); +void* runtime_lfstackpop(uint64 *head) + __asm__ (GOSYM_PREFIX "runtime.lfstackpop"); /* * Parallel for over [0, n). -- 2.30.2