//! # smarm — Silly Marks Abstract Rust Machine //! //! Erlang-style green-thread actor concurrency for Rust. //! //! Single-threaded for now: one scheduler, one OS thread. The scheduler //! cooperatively interleaves green-thread actors with hand-rolled context //! switches. Actors communicate by sending `Send` messages over channels; //! every actor has a supervisor, which is itself just an actor with a //! `Receiver`. Synchronisation primitives — `Mutex` with //! mandatory lock timeouts, channel `recv`, `sleep`, and epoll-backed //! `wait_readable`/`wait_writable` — all park the green thread, never //! the OS thread. //! //! See `LOOM.md` for the design intent and the deferred-for-later list. pub mod stack; pub mod context; pub mod preempt; pub mod pid; pub mod actor; pub mod channel; pub mod scheduler; pub mod supervisor; pub mod timer; pub mod io; pub mod mutex; // --------------------------------------------------------------------------- // Global allocator // // The preempting allocator wraps `System`. While `PREEMPTION_ENABLED` is // false (the default outside an actor) it adds one branch per allocation // and no syscalls. The scheduler flips it on per-resume. // --------------------------------------------------------------------------- #[global_allocator] static ALLOCATOR: preempt::PreemptingAllocator = preempt::PreemptingAllocator; // --------------------------------------------------------------------------- // Public API re-exports // --------------------------------------------------------------------------- pub use channel::{channel, Receiver, RecvError, Sender}; pub use mutex::{LockTimeout, Mutex, MutexGuard}; pub use pid::Pid; pub use scheduler::{ block_on_io, run, self_pid, sleep, spawn, spawn_under, wait_readable, wait_writable, yield_now, JoinError, JoinHandle, }; // `read` and `write` would shadow heavily-used names if re-exported at the // crate root; users reach for them as `smarm::scheduler::read` / // `smarm::scheduler::write` instead. May reshuffle into a `smarm::io` // surface in a future pass. pub use supervisor::Signal; // --------------------------------------------------------------------------- // check!() — explicit preemption point for tight no-alloc loops. // --------------------------------------------------------------------------- /// Voluntarily check whether this actor's timeslice has expired, yielding /// if so. Drop this into hot compute loops that don't allocate (heap or /// large stack frames) — without it, such loops monopolise the scheduler /// until they return. /// /// Decrements the same per-actor event counter as the heap allocator's /// preemption hook, so the check rate is identical regardless of whether /// the actor is alloc-heavy, check-heavy, or mixed. /// /// No-op outside an actor (the runtime's `PREEMPTION_ENABLED` flag is /// false there). #[macro_export] macro_rules! check { () => { $crate::preempt::maybe_preempt() }; }