dtact 0.2.5

Dtact: A non-preemptive, stackful coroutine runtime featuring a lock-free context arena, P2P mesh scheduling, and architecture-specific assembly switchers. Designed for hardware-level control and non-blocking heterogeneous orchestration.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
//! # Dtact-V3: Distributed Task-Aware Coroutine Toolkit
//!
//! Dtact is a high-performance, low-latency asynchronous runtime designed for systems-level
//! programming across heterogeneous architectures (`x86_64`, `AArch64`, `RISC-V`).
//!
//! ## Core Architecture
//! 1. **Lock-Free Arena**: A page-aligned memory pool for fiber contexts, providing O(1) allocation
//!    and hardware-level guard pages for memory safety.
//! 2. **P2P Scheduler Mesh**: A distributed work-stealing/deflection scheduler that minimizes L3
//!    cache thrashing and maximizes NUMA-local execution.
//! 3. **Zero-Copy Migration**: Leveraging self-referential futures and direct stack-top injection
//!    to move running tasks across cores without heap allocation.
//!
//! Dtact provides tiered safety levels (0-2) allowing developers to trade off between raw
//! performance and hardware-enforced isolation (e.g., guard pages and SEH registration).

// =========================================================================
// RUST LINT CONFIGURATION: dtact
// =========================================================================

// -------------------------------------------------------------------------
// LEVEL 1: CRITICAL ERRORS (Deny)
// -------------------------------------------------------------------------
#![deny(
    unreachable_code,
    improper_ctypes_definitions,
    future_incompatible,
    nonstandard_style,
    rust_2018_idioms,
    clippy::perf,
    clippy::correctness,
    clippy::suspicious,
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::indexing_slicing,
    clippy::arithmetic_side_effects,
    clippy::missing_safety_doc,
    clippy::same_item_push,
    clippy::implicit_clone,
    clippy::all,
    clippy::pedantic,
    missing_docs,
    clippy::nursery,
    clippy::single_call_fn
)]
// -------------------------------------------------------------------------
// LEVEL 2: STYLE WARNINGS (Warn)
// -------------------------------------------------------------------------
#![warn(
    dead_code,
    warnings,
    clippy::dbg_macro,
    clippy::todo,
    clippy::cast_possible_truncation,
    clippy::cast_sign_loss,
    clippy::cast_possible_wrap,
    clippy::unnecessary_safety_comment
)]
// -------------------------------------------------------------------------
// LEVEL 3: ALLOW/IGNORABLE (Allow)
// -------------------------------------------------------------------------
#![allow(
    unsafe_code,
    unused_unsafe,
    private_interfaces,
    clippy::restriction,
    clippy::inline_always,
    unused_doc_comments,
    clippy::empty_line_after_doc_comments,
    clippy::missing_const_for_thread_local
)]
#![crate_name = "dtact"]

extern crate alloc;

/// Set the deflection threshold for the DTA-V3 Scheduler.
pub use crate::api::config::set_deflection_threshold;
/// Spawn a fiber with a custom stack size.
pub use crate::api::fiber::spawn_with_stack;
/// Yield execution to another fiber.
pub use crate::api::fiber::yield_to as yield_to_sync;
/// Hardware-level demotion API.
#[cfg(feature = "hw-acceleration")]
pub use crate::api::hw::cldemote;
/// Hardware-level interrupt signaling API.
#[cfg(feature = "hw-acceleration")]
pub use crate::api::hw::uintr_signal as uintr;
/// Spawn a fiber.
pub use crate::api::spawn;
/// Spawn a fiber.
///
/// This macro supports both standard futures and custom tasks defined via `#[task]`.
#[macro_export]
macro_rules! spawn {
    ($fut:expr) => {{
        #[allow(unused_imports)]
        use $crate::api::spawner_traits::FallbackSpawner as _;
        $crate::api::spawner_traits::SpawnerTag.spawn($fut)
    }};
}
/// Yield execution to the scheduler.
pub use crate::api::yield_now;
/// Yield execution to another fiber.
#[doc(hidden)]
pub use crate::api::yield_to;
/// Yield execution to another fiber.
pub use crate::api::yield_to as yield_to_async;
/// Wait for a fiber to complete.
pub use crate::c_ffi::dtact_await;
/// Handle for C-compatible FFI.
pub use crate::c_ffi::dtact_handle_t;
/// Wait for a fiber to complete.
#[doc(hidden)]
pub use crate::future_bridge::wait;
/// Wait for a fiber to complete.
pub use crate::future_bridge::wait as dtact_wait;
/// Attribute macro for initializing the Dtact runtime.
pub use dtact_macros::dtact_init;
/// Attribute macro for exporting an async function to C.
pub use dtact_macros::export_async;
/// Attribute macro for exporting a fiber to C.
pub use dtact_macros::export_fiber;
/// Attribute macro for defining a Dtact task.
pub use dtact_macros::task;

/// Public user-facing API for spawning and managing fibers.
#[doc(hidden)]
pub mod api;
/// C-compatible FFI boundary for cross-language integration.
#[doc(hidden)]
pub mod c_ffi;
/// Common types used across the Dtact runtime.
#[doc(hidden)]
pub mod common_types;
/// Low-level assembly-based context switching primitives.
#[doc(hidden)]
pub mod context_switch;
/// Distributed P2P Mesh scheduler implementation.
#[doc(hidden)]
pub mod dta_scheduler;
/// Bridge for polling futures within a `FiberContext`.
#[doc(hidden)]
pub mod future_bridge;
/// Lock-free arena and OS-level memory management.
#[doc(hidden)]
pub mod memory_management;
/// Timing, topology, and OS-specific primitives.
#[doc(hidden)]
pub mod utils;

pub use api::*;

/// DTA-V3 Runtime Environment.
///
/// Consolidates the distributed scheduler and the memory pool into a single
/// unit to ensure architectural consistency across all worker threads.
#[doc(hidden)]
pub struct Runtime {
    /// The distributed P2P work-deflection scheduler.
    pub scheduler: dta_scheduler::DtaScheduler,
    /// The lock-free arena for managing fiber stacks and contexts.
    pub pool: memory_management::ContextPool,
    /// Flag indicating if the worker threads have been started.
    pub started: crate::sync::atomic::AtomicBool,
    /// Cooperative shutdown signal for worker threads.
    pub shutdown: crate::sync::atomic::AtomicBool,
}

impl Runtime {
    /// Spawns the OS worker threads for the scheduler.
    ///
    /// # Panics
    ///
    /// Panics if the system fails to spawn a new thread. This can occur if
    /// the operating system limits on the number of threads have been reached.
    pub fn start(&'static self) {
        if self
            .started
            .swap(true, crate::sync::atomic::Ordering::SeqCst)
        {
            return;
        }

        let workers_count = self.scheduler.workers.len();

        for i in 0..workers_count {
            // Each closure must capture its own copy of these values.
            let sched: &'static dta_scheduler::DtaScheduler = &self.scheduler;
            let pool: &'static memory_management::ContextPool = &self.pool;
            let shutdown: &'static crate::sync::atomic::AtomicBool = &self.shutdown;
            let my_id = i;

            std::thread::Builder::new()
                .name(format!("dtact-worker-{my_id}"))
                .spawn(move || {
                    crate::dta_scheduler::DtaScheduler::run_worker_static(
                        sched, my_id, pool, shutdown,
                    );
                })
                .expect("Failed to spawn Dtact worker thread");
        }
    }
}

/// Global Singleton for the Runtime Environment.
///
/// This is initialized exactly once per process via `dtact_init` or
/// implicit autostart triggers in the proc-macro layer.
#[doc(hidden)]
pub static GLOBAL_RUNTIME: std::sync::OnceLock<Runtime> = std::sync::OnceLock::new();

/// Telemetry: Tracks fibers that failed the 8KB zero-copy check and fell back to heap allocation.
///
/// A high value indicates that captured future sizes exceed the pre-allocated
/// stack-top buffer, causing a performance cliff due to heap traffic.
#[doc(hidden)]
pub static HEAP_ESCAPED_SPAWNS: core::sync::atomic::AtomicU64 =
    core::sync::atomic::AtomicU64::new(0);

/// Awakens a fiber by pushing it onto the scheduler mesh.
///
/// Dispatches between `enqueue_pinned` and `enqueue_deflect` based on the
/// fiber's stored `mode`. Pinned fibers (`SameThread` switchers) skip the
/// deflection hash and route strictly to their `origin_core`; deflectable
/// fibers (`CrossThread` switchers) consult load and may hop / spill to the
/// warehouse. The mode is set at spawn time and never changes.
///
/// # Arguments
/// * `origin_core` - The core ID where the fiber was originally spawned.
/// * `fiber_index` - The unique identifier of the fiber in the context pool.
#[inline(always)]
pub(crate) fn wake_fiber(origin_core: usize, fiber_index: u32) {
    let runtime = GLOBAL_RUNTIME
        .get()
        .expect("dtact::wake_fiber() invoked before Runtime Initialization");
    let pool = &runtime.pool;
    let ctx_ptr = pool.get_context_ptr(fiber_index);
    let pinned = matches!(
        unsafe { (*ctx_ptr).mode },
        common_types::TopologyMode::Pinned
    ) || matches!(
        unsafe { (*ctx_ptr).affinity },
        crate::api::topology::Affinity::SameCore
    );
    let affinity = unsafe { (*ctx_ptr).affinity };

    loop {
        // Two-entry function-pointer table — branchless after the bool is computed.
        type EnqFn = fn(
            &dta_scheduler::DtaScheduler,
            usize,
            u64,
            u32,
            crate::api::topology::Affinity,
        ) -> bool;
        const ENQUEUE_FNS: [EnqFn; 2] = [enqueue_deflect_shim, enqueue_pinned_shim];
        let success = ENQUEUE_FNS[usize::from(pinned)](
            &runtime.scheduler,
            origin_core,
            u64::from(fiber_index),
            fiber_index,
            affinity,
        );
        if success {
            return;
        }

        // Backpressure: enqueue_pinned can fail when the target's local queue
        // is over the watermark AND the cross-core mailbox is full.
        // (enqueue_deflect never returns false — it either places in a mailbox
        //  or panics via warehouse overflow.) Yield to give the scheduler a
        // chance to drain, then retry.
        backpressure_yield();
    }
}

#[inline(always)]
fn enqueue_pinned_shim(
    sched: &dta_scheduler::DtaScheduler,
    target: usize,
    _flow: u64,
    task: u32,
    _affinity: crate::api::topology::Affinity,
) -> bool {
    sched.enqueue_pinned(target, task)
}

#[inline(always)]
fn enqueue_deflect_shim(
    sched: &dta_scheduler::DtaScheduler,
    source: usize,
    flow: u64,
    task: u32,
    affinity: crate::api::topology::Affinity,
) -> bool {
    sched.enqueue_deflect(source, flow, task, affinity)
}

/// State-guarded fiber wake by pool index.
///
/// Atomically swaps the target's `state` to `Notified`. Only enqueues
/// the fiber via [`wake_fiber`] when the prior state was `Yielded`
/// (the fiber is parked off-CPU and needs a worker to re-dispatch it).
///
/// For `Running` / `Suspending` the fiber is currently held by a worker;
/// that worker's `dispatch_loop` observes `Notified` after `switch_fn`
/// returns and re-pushes via `push_local`. Skipping the redundant
/// external enqueue is what prevents a double-dispatch race on
/// deflectable (`CrossThread`) fibers — without the guard, the same
/// fiber index could land in two workers' queues, both call `switch_fn`
/// into the same stack concurrently, clobber `executor_regs`, and leave
/// one worker permanently stranded inside the fiber.
///
/// Mirrors the protocol applied inline by
/// [`future_bridge::wake_by_ref_impl`](crate::future_bridge); the only
/// difference is that this helper resolves the context via the pool
/// because callers only hold the index, not a `&FiberContext`.
///
/// MUST NOT be used by spawn paths, which intentionally publish a new
/// fiber while it is still in `Running` and rely on the unconditional
/// `wake_fiber` enqueue for first dispatch.
#[inline(always)]
pub(crate) fn awaken_fiber_by_index(target_worker: usize, fiber_index: u32) {
    let runtime = GLOBAL_RUNTIME
        .get()
        .expect("dtact::awaken_fiber_by_index() invoked before Runtime Initialization");
    let ctx_ptr = runtime.pool.get_context_ptr(fiber_index);
    let prev = unsafe {
        (*ctx_ptr).state.swap(
            crate::memory_management::FiberStatus::Notified as u32,
            core::sync::atomic::Ordering::AcqRel,
        )
    };
    if prev == crate::memory_management::FiberStatus::Yielded as u32 {
        wake_fiber(target_worker, fiber_index);
    }
}

/// Resolves an opaque waiter handle (encoded by `dtact_await`'s fiber path)
/// and conditionally re-enqueues the waiting fiber via the state-guarded
/// wake protocol — see [`awaken_fiber_by_index`] for the protocol details
/// and the double-dispatch race it prevents.
#[inline(always)]
pub(crate) fn wake_waiter_handle(packed: u64) {
    let waiter = packed & !(1u64 << 63);
    let fiber_index = (waiter & 0xFFFF_FFFF) as u32;
    // The stored `target_worker` is the worker the waiter was running on
    // when it suspended — used as the routing source for `enqueue_deflect`
    // if we actually need to enqueue.
    let target_worker = (waiter >> 32) as usize;
    awaken_fiber_by_index(target_worker, fiber_index);
}

/// Backpressure handler: cooperative yield if inside a fiber, brief
/// spin + OS yield if on a host thread.
#[inline]
fn backpressure_yield() {
    let ctx_ptr = crate::future_bridge::CURRENT_FIBER.with(std::cell::Cell::get);
    if ctx_ptr.is_null() {
        for _ in 0..32 {
            core::hint::spin_loop();
        }
        std::thread::yield_now();
    } else {
        unsafe {
            let ctx = &mut *ctx_ptr;
            ctx.state.store(
                crate::memory_management::FiberStatus::Notified as u32,
                crate::sync::atomic::Ordering::Release,
            );
            (ctx.switch_fn)(&raw mut ctx.regs, &raw const ctx.executor_regs);
        }
    }
}

#[cfg(loom)]
#[allow(unused_imports)]
pub(crate) mod sync {
    pub(crate) mod atomic {
        pub(crate) use loom::sync::atomic::fence;
        pub(crate) use loom::sync::atomic::{
            AtomicBool, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, Ordering,
        };
    }
    pub(crate) use loom::sync::Arc;
    pub(crate) use loom::thread;
}

#[cfg(not(loom))]
#[allow(unused_imports)]
pub(crate) mod sync {
    pub mod atomic {
        pub use core::sync::atomic::{
            AtomicBool, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, Ordering,
        };
        pub use std::sync::atomic::fence;
    }
    pub use std::sync::Arc;
    pub use std::thread;
}

#[allow(clippy::mixed_attributes_style)]
#[cfg_attr(miri, ignore)]
#[doc(hidden)]
mod readme {
    #![doc = include_str!("../README.md")]
}