Skip to main content

Runtime

Struct Runtime 

Source
pub struct Runtime { /* private fields */ }
Expand description

Single-threaded async runtime.

Runtime is intrinsically thread-bound — its slab TLS state is per-thread, so moving it to another thread would silently desynchronize allocation dispatch. The type is therefore both !Send and !Sync, enforced by a PhantomData<*const ()> marker.

use nexus_async_rt::Runtime;
fn assert_send<T: Send>() {}
assert_send::<Runtime>();
use nexus_async_rt::Runtime;
fn assert_sync<T: Sync>() {}
assert_sync::<Runtime>();

§Examples

use nexus_async_rt::{Runtime, spawn_boxed, spawn_slab};
use nexus_slab::byte::unbounded::Slab;
use nexus_rt::WorldBuilder;

let mut world = WorldBuilder::new().build();

// Simple — Box-allocated tasks
let mut rt = Runtime::new(&mut world);
rt.block_on(async {
    spawn_boxed(async { /* Box-allocated */ });
});

// With slab for hot-path tasks
let slab = unsafe { Slab::<256>::with_chunk_capacity(64) };
let mut rt = Runtime::builder(&mut world)
    .slab_unbounded(slab)
    .build();
rt.block_on(async {
    spawn_boxed(async { /* Box-allocated */ });
    spawn_slab(async { /* slab-allocated */ });
});

Implementations§

Source§

impl Runtime

Source

pub fn new(world: &mut World) -> Self

Create a runtime with default settings. Box-allocated tasks only.

For slab allocation or custom configuration, use Runtime::builder.

Source

pub fn builder(world: &mut World) -> RuntimeBuilder<'_>

Create a runtime via the builder pattern.

Source

pub fn shutdown_handle(&self) -> ShutdownHandle

Returns a ShutdownHandle for triggering or observing shutdown.

Source

pub fn install_signal_handlers(&self)

Install signal handlers for SIGTERM and SIGINT.

Source

pub fn task_count(&self) -> usize

Number of live spawned tasks.

Source

pub fn shutdown_stats(&self) -> Arc<ShutdownStatsAtomics>

Returns a handle to the abnormal-shutdown counter atomics. Hold the handle past drop(runtime) to inspect final values — the counters fire DURING Executor::drop, so a snapshot taken before drop will show all zeros for the shutdown-only counters.

Useful as a signal — if any counter is non-zero, the shutdown hit a defensive path that should be investigated.

let stats_handle = runtime.shutdown_stats();
drop(runtime);
let stats = stats_handle.snapshot();
if stats.aborted_unwinds != 0
    || stats.leaked_box_tasks != 0
    || stats.unbalanced_normal_shutdowns != 0
    || stats.cross_queue_undrained != 0
{
    // user's own observability — log to wherever they want
    my_logger::warn!("nexus runtime shutdown: {stats:?}");
}

Per PR 2’s design (CALLOUT 5 of the plan), the runtime emits no log events of its own when these counters fire — users own their observability stack. The PR 1a eprintln! calls in the slab-unwinding-abort path remain (the only signal at the moment of process abort) but new abnormal paths added in PR 2 are pure counter increments.

§Counters

See ShutdownStats for what each counter signifies, and [ShutdownStatsAtomics::snapshot] for the read API on the returned handle.

Source§

impl Runtime

Source

pub fn block_on<F>(&mut self, future: F) -> F::Output
where F: Future + 'static,

Drive the root future to completion. CPU-friendly.

Parks the thread when no work is available.

Source

pub fn block_on_busy<F>(&mut self, future: F) -> F::Output
where F: Future + 'static,

Drive the root future to completion. Busy-wait.

Never parks. Minimum wake latency at 100% CPU.

Source

pub fn shutdown_quiesce( &mut self, timeout: Duration, ) -> Result<(), QuiesceTimeout>

Drive the executor until pending cross-thread work has settled, before shutdown. The canonical “quiesce” step before drop(runtime) — see docs/SHUTDOWN.md for the full pattern.

Loops while:

  1. The cross-thread queue has entries (drains them).
  2. The local ready queue has entries (polls them).

Returns Ok(()) once both are empty (or detected to no longer receive new entries). Returns Err(QuiesceTimeout) if timeout elapses first; the error contains diagnostic counts useful for determining which producer didn’t release its refs.

This is for clean shutdown, not panic-during-shutdown. The 100ms unwinding-wait in Executor::drop remains as defense-in-depth for the panic case (where this method can’t be called).

The timeout parameter has no default — callers must pick a budget deliberately. PR 2 §2.4 open-item 4 evaluated 100ms (matches the unwinding defense), 500ms (forgiving), and “parameter-only” — chose parameter-only to force the user to pick a budget appropriate for their producer landscape (a trading-system shutdown sequence with multiple Aeron drivers plus tokio futures plus channel senders has very different settling characteristics than a unit test).

§Canonical shutdown sequence
// 1. Stop producers of cross-thread refs:
//    - Drop tokio runtime (or shutdown_timeout)
//    - Stop Aeron driver thread
//    - Drop external channel senders

// 2. Quiesce.
runtime.shutdown_quiesce(Duration::from_millis(500))?;

// 3. Drop the Runtime. Outstanding-ref panic paths in
//    Executor::drop should be unreachable in normal operation.
drop(runtime);

If step 2 returns QuiesceTimeout, a producer hasn’t released its refs. Investigate before letting Runtime drop — the unwind-abort path in Executor::drop is defensive, not desired.

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.

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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.