// 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

import (
	
	
)

// 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
// must ensure the nodes are allocated outside the Go heap.
type lfstack uint64

func ( *lfstack) ( *lfnode) {
	.pushcnt++
	 := lfstackPack(, .pushcnt)
	for {
		 := atomic.Load64((*uint64)())
		.next = 
		if atomic.Cas64((*uint64)(), , ) {
			break
		}
	}
}

func ( *lfstack) () unsafe.Pointer {
	var  uint32
	// TODO: tweak backoff parameters on other architectures.
	if GOARCH == "arm64" {
		 = 128
	}
	for {
		 := atomic.Load64((*uint64)())
		if  == 0 {
			return nil
		}
		 := lfstackUnpack()
		 := atomic.Load64(&.next)
		if atomic.Cas64((*uint64)(), , ) {
			return unsafe.Pointer()
		}

		// Use a backoff approach to reduce demand to the shared memory location
		// decreases memory contention and allows for other threads to make quicker
		// progress.
		// Read more in this Arm blog post:
		// https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/multi-threaded-applications-arm
		procyield()
		// Increase backoff time.
		 +=  / 2

	}
}

func ( *lfstack) () bool {
	return atomic.Load64((*uint64)()) == 0
}

// lfnodeValidate panics if node is not a valid address for use with
// lfstack.push. This only needs to be called when node is allocated.
func lfnodeValidate( *lfnode) {
	if , ,  := findObject(uintptr(unsafe.Pointer()), 0, 0);  != 0 {
		throw("lfstack node allocated from the heap")
	}
	lfstackPack(, ^uintptr(0))
}

func lfstackPack( *lfnode,  uintptr) uint64 {
	return uint64(taggedPointerPack(unsafe.Pointer(), &(1<<tagBits-1)))
}

func lfstackUnpack( uint64) *lfnode {
	return (*lfnode)(taggedPointer().pointer())
}