Commit e597e053 by Ian Lance Taylor

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
parent 16b61424
14dc8052a09ad0a2226e64ab6b5af69c6923b830 df6046971233854e5b7533140d4ead095ab69857
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -488,7 +488,6 @@ runtime_files = \ ...@@ -488,7 +488,6 @@ runtime_files = \
$(runtime_thread_files) \ $(runtime_thread_files) \
runtime/yield.c \ runtime/yield.c \
$(rtems_task_variable_add_file) \ $(rtems_task_variable_add_file) \
lfstack.c \
malloc.c \ malloc.c \
runtime1.c \ runtime1.c \
sigqueue.c \ sigqueue.c \
......
...@@ -252,8 +252,8 @@ am__objects_5 = go-append.lo go-assert.lo go-breakpoint.lo \ ...@@ -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 \ env_posix.lo heapdump.lo mcache.lo mcentral.lo \
$(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.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 \ panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
thread.lo $(am__objects_2) yield.lo $(am__objects_3) \ thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
lfstack.lo malloc.lo runtime1.lo sigqueue.lo $(am__objects_4) runtime1.lo sigqueue.lo $(am__objects_4)
am_libgo_llgo_la_OBJECTS = $(am__objects_5) am_libgo_llgo_la_OBJECTS = $(am__objects_5)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS) libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
...@@ -884,7 +884,6 @@ runtime_files = \ ...@@ -884,7 +884,6 @@ runtime_files = \
$(runtime_thread_files) \ $(runtime_thread_files) \
runtime/yield.c \ runtime/yield.c \
$(rtems_task_variable_add_file) \ $(rtems_task_variable_add_file) \
lfstack.c \
malloc.c \ malloc.c \
runtime1.c \ runtime1.c \
sigqueue.c \ sigqueue.c \
...@@ -1562,7 +1561,6 @@ distclean-compile: ...@@ -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-unwind.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.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)/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_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)/libgobegin_llgo_a-go-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgolibbegin_a-go-libmain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgolibbegin_a-go-libmain.Po@am__quote@
......
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
package runtime package runtime
import (
"unsafe"
)
//var Fadd64 = fadd64 //var Fadd64 = fadd64
//var Fsub64 = fsub64 //var Fsub64 = fsub64
//var Fmul64 = fmul64 //var Fmul64 = fmul64
...@@ -32,11 +36,13 @@ type LFNode struct { ...@@ -32,11 +36,13 @@ type LFNode struct {
Pushcnt uintptr Pushcnt uintptr
} }
func lfstackpush_go(head *uint64, node *LFNode) func LFStackPush(head *uint64, node *LFNode) {
func lfstackpop_go(head *uint64) *LFNode lfstackpush(head, (*lfnode)(unsafe.Pointer(node)))
}
var LFStackPush = lfstackpush_go func LFStackPop(head *uint64) *LFNode {
var LFStackPop = lfstackpop_go return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
}
type ParFor struct { type ParFor struct {
body func(*ParFor, uint32) body func(*ParFor, uint32)
......
// 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)
}
}
}
// 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)))
}
...@@ -2,9 +2,7 @@ ...@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build ignore // +build amd64 arm64 mips64 mips64le ppc64 ppc64le s390x arm64be alpha mipsn64 sparc64
// +build amd64 arm64 mips64 mips64le ppc64 ppc64le s390x
package runtime package runtime
...@@ -41,8 +39,8 @@ func lfstackPack(node *lfnode, cnt uintptr) uint64 { ...@@ -41,8 +39,8 @@ func lfstackPack(node *lfnode, cnt uintptr) uint64 {
} }
func lfstackUnpack(val uint64) *lfnode { func lfstackUnpack(val uint64) *lfnode {
if GOARCH == "amd64" { if GOARCH == "amd64" || GOOS == "solaris" {
// amd64 systems can place the stack above the VA hole, so we need to sign extend // amd64 or Solaris systems can place the stack above the VA hole, so we need to sign extend
// val before unpacking. // val before unpacking.
return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3))) return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3)))
} }
......
// 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)-1)));
}
static inline LFNode* lfUnpack(uint64 val) {
return (LFNode*)((val >> 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);
}
...@@ -67,7 +67,7 @@ typedef struct FixAlloc FixAlloc; ...@@ -67,7 +67,7 @@ typedef struct FixAlloc FixAlloc;
typedef struct hchan Hchan; typedef struct hchan Hchan;
typedef struct timer Timer; typedef struct timer Timer;
typedef struct gcstats GCStats; typedef struct gcstats GCStats;
typedef struct LFNode LFNode; typedef struct lfnode LFNode;
typedef struct ParFor ParFor; typedef struct ParFor ParFor;
typedef struct ParForThread ParForThread; typedef struct ParForThread ParForThread;
typedef struct cgoMal CgoMal; typedef struct cgoMal CgoMal;
...@@ -178,13 +178,6 @@ enum { ...@@ -178,13 +178,6 @@ enum {
}; };
#endif #endif
// Lock-free stack node.
struct LFNode
{
LFNode *next;
uintptr pushcnt;
};
// Parallel for descriptor. // Parallel for descriptor.
struct ParFor struct ParFor
{ {
...@@ -461,7 +454,8 @@ bool runtime_notetsleepg(Note*, int64) // false - timeout ...@@ -461,7 +454,8 @@ bool runtime_notetsleepg(Note*, int64) // false - timeout
*/ */
void runtime_lfstackpush(uint64 *head, LFNode *node) void runtime_lfstackpush(uint64 *head, LFNode *node)
__asm__ (GOSYM_PREFIX "runtime.lfstackpush"); __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). * Parallel for over [0, n).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment