diff options
| author | Austin Clements <austin@google.com> | 2017-03-07 16:38:29 -0500 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2017-03-19 22:42:24 +0000 |
| commit | 13ae271d5d007dcd630d9f43d6a43016b9af6e5c (patch) | |
| tree | e49da3d7b91e5a729a717ee60b9e6025d67f6063 /src/runtime/lfstack.go | |
| parent | 2805d206890344f685579ac5b72ba2d9e5da485d (diff) | |
| download | go-13ae271d5d007dcd630d9f43d6a43016b9af6e5c.tar.xz | |
runtime: introduce a type for lfstacks
The lfstack API is still a C-style API: lfstacks all have unhelpful
type uint64 and the APIs are package-level functions. Make the code
more readable and Go-style by creating an lfstack type with methods
for push, pop, and empty.
Change-Id: I64685fa3be0e82ae2d1a782a452a50974440a827
Reviewed-on: https://go-review.googlesource.com/38290
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Rick Hudson <rlh@golang.org>
Diffstat (limited to 'src/runtime/lfstack.go')
| -rw-r--r-- | src/runtime/lfstack.go | 35 |
1 files changed, 23 insertions, 12 deletions
diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go index 8e33ce1d09..4787c5be3f 100644 --- a/src/runtime/lfstack.go +++ b/src/runtime/lfstack.go @@ -3,10 +3,6 @@ // 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 @@ -15,32 +11,47 @@ import ( "unsafe" ) -func lfstackpush(head *uint64, node *lfnode) { +// lfstack is the head of a lock-free stack. +// +// The zero value of lfstack is an empty list. +// +// This stack is intrusive. Nodes must embed lfnode as the first field. +// +// The stack does not keep GC-visible pointers to nodes, so the caller +// is responsible for ensuring the nodes are not garbage collected +// (typically by allocating them from manually-managed memory). +type lfstack uint64 + +func (head *lfstack) push(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") + print("runtime: lfstack.push invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n") + throw("lfstack.push") } for { - old := atomic.Load64(head) + old := atomic.Load64((*uint64)(head)) node.next = old - if atomic.Cas64(head, old, new) { + if atomic.Cas64((*uint64)(head), old, new) { break } } } -func lfstackpop(head *uint64) unsafe.Pointer { +func (head *lfstack) pop() unsafe.Pointer { for { - old := atomic.Load64(head) + old := atomic.Load64((*uint64)(head)) if old == 0 { return nil } node := lfstackUnpack(old) next := atomic.Load64(&node.next) - if atomic.Cas64(head, old, next) { + if atomic.Cas64((*uint64)(head), old, next) { return unsafe.Pointer(node) } } } + +func (head *lfstack) empty() bool { + return atomic.Load64((*uint64)(head)) == 0 +} |
