Skip to main content

StackHead

Struct StackHead 

Source
pub struct StackHead<const INDEX_BITS: u32> { /* private fields */ }
Expand description

The head word of a tagged Treiber free-list: a single AtomicU64 packing an (index | tag) pair (see TaggedIndex). Owned by exactly one StackStorage implementor value at a time, and bound to one link backing for its WHOLE life — the binding between this head and its links is established by that impl, not re-asserted per call; sharing one head between implementor values (clause 1) or rebinding a live head across time are hazards — see the StackStorage trait’s # Safety contract. The stack operations themselves live on StackOps (blanket-implemented by the crate), not here; this type is the bare atomic embedders inherit a cache line through.

§Layout note — no cache-line isolation

This type is a bare AtomicU64 with no padding or alignment of its own — #[repr(transparent)] makes that a compiler-enforced guarantee (layout, size, and ABI identical to the single head field), not an incidental property of the current definition — so it inherits the cache line of whatever struct embeds it. If it lands adjacent to another frequently-modified atomic, the two fields false-share — each write invalidates the other core’s copy of the line, and contending cores ping-pong the line even though the atomics are logically independent. That costs throughput, never correctness, and only matters when the line is genuinely hot. Fix it at the embedding site when a profile shows it — wrap this stack in a #[repr(align(64))] newtype or interpose padding — rather than paying for blanket alignment inside the crate, which would waste most of a cache line for every embedder that does not need the isolation.

§Sealing is permanent — no reset

Once pushes_remaining reaches 0 (the tag is TaggedIndex::TAG_MAX), this head is sealed and stays sealed: there is no reset/rotation API, and none will be added. An in-place reset would be a plain store on head — breaking the release-sequence invariant documented on the private field below — AND would restore tag 0, reintroducing the exact full-wrap collision this seal exists to close (see the crate-root docs’ tag-preservation note on why a naive tag reset is unsound in general). A sealed head cannot be reset. A replacement must be a distinct StackHead object; if it reuses the same link cells and index population, the sealed head must first be fully drained (pop_indexNone repeatedly until empty) and must outlive every popper that may still reference it — for a 'static head, forever.

Implementations§

Source§

impl<const INDEX_BITS: u32> StackHead<INDEX_BITS>

Source

pub const fn new() -> Self

A fresh, EMPTY stack head (the bootstrap empty sentinel, tag 0). Under --cfg loom this cannot be const (loom’s atomics have no const ctor).

Source

pub fn is_empty(&self) -> bool

Whether the stack is currently empty. Advisory only — a concurrent push or pop can make the answer stale the instant this returns, in either direction — so use it for diagnostics/monitoring, not for correctness decisions (pop_index’s None is the authoritative empty check).

A Relaxed load is sufficient here because the result is explicitly racy: no ordering is being promised, and a plain load touches nothing, so the release-sequence invariant documented on the private head field is untouched.

Source

pub fn pushes_remaining(&self) -> u64

Successful pushes this head can still accept before push_index starts refusing with Err(TagExhausted): TaggedIndex::TAG_MAX - tag. 0 means sealed — every future push is refused (see “Sealing is permanent” above).

Advisory Relaxed load, same posture as is_empty: a concurrent push can make this stale the instant it returns. A plain load touches nothing, so the release-sequence invariant on the private head field (see its doc) is untouched.

Trait Implementations§

Source§

impl<const INDEX_BITS: u32> Debug for StackHead<INDEX_BITS>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<const INDEX_BITS: u32> Default for StackHead<INDEX_BITS>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<const INDEX_BITS: u32> !Freeze for StackHead<INDEX_BITS>

§

impl<const INDEX_BITS: u32> RefUnwindSafe for StackHead<INDEX_BITS>

§

impl<const INDEX_BITS: u32> Send for StackHead<INDEX_BITS>

§

impl<const INDEX_BITS: u32> Sync for StackHead<INDEX_BITS>

§

impl<const INDEX_BITS: u32> Unpin for StackHead<INDEX_BITS>

§

impl<const INDEX_BITS: u32> UnsafeUnpin for StackHead<INDEX_BITS>

§

impl<const INDEX_BITS: u32> UnwindSafe for StackHead<INDEX_BITS>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.