Skip to main content

ReleaseTimer

Struct ReleaseTimer 

Source
pub(crate) struct ReleaseTimer {
    inner: Arc<Inner>,
    thread: Option<JoinHandle<()>>,
}
Expand description

An owned release wheel: one OS thread, one heap, one parker.

The process-wide wheel is one of these in a OnceLock. Instances created directly (this module’s tests today, per-socket owners later) join their thread on drop — unless the drop is itself running on that thread, which the Drop impl below explains.

Fields§

§inner: Arc<Inner>§thread: Option<JoinHandle<()>>

Implementations§

Source§

impl ReleaseTimer

Source

pub(crate) fn new() -> Self

Resolve a backend and start the release thread.

Honours MOQTAP_RELEASE_TIMER (slice | condvar), read once, here. Unset or unrecognised means slice. Cannot fail, and that is a property of the design rather than an omission: there is no OS object to fail to create, so there is no fallback ladder and no error path to test.

Source

pub(crate) fn arm(&self, at: Instant) -> Deadline

Register at. at <= now yields an already-cancelled Deadline without touching the heap or waking the thread.

Source

pub(crate) fn backend(&self) -> TimerBackend

Which primitive this wheel’s thread waits on.

Trait Implementations§

Source§

impl Drop for ReleaseTimer

Sets stopping, wakes the thread, and joins it — except when the drop is itself running on that thread, where it detaches instead. Pending deadlines are abandoned, not fired: a dropped wheel has no listeners left.

§Why the join is conditional

The join is cheap only from another thread. Measured 0.097 ms with a 10 s deadline armed, because the thread never waits longer than one SLICE and so reads stopping promptly — but that measurement was taken with the wheel dropped from a thread other than its own release thread, and it licenses nothing about the other case. It was the only case anything could reach while the never-dropped process-wide wheel was the sole non-test owner; a wheel owned per socket is droppable from anywhere.

From the release thread the join is not a slow path, it is a permanent deadlock. Step 3 of run cancels tokens outside the lock and on the release thread, so every waker registered on a deadline — which is what awaiting token().cancelled() installs — runs there too. A waker that drops the last handle to the wheel enters this function on the release thread, and join() then waits for the thread executing it. stopping and notify_all do not rescue it: the thread is inside the cancel loop and can never return to the top of run to read the flag. Measured that way, the drop had not returned after 20 s against a 500 µs SLICE, on every run.

Detaching there is not a compromise, it is the only outcome that terminates. stopping is set and notify_all sent before the branch, so the detached thread finishes the cancel loop it is in, sees the flag on its next iteration and returns on its own: a bounded, self-clearing thread rather than an unbounded hang. The handle already carries the id spawn gave the thread, so no separate field is needed to recognise it.

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

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.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more