Add epoll-based non-blocking I/O and kernel-like mutexes: - src/io.rs: Complete epoll backend with timeout & error handling - src/mutex.rs: Fair mutex with waiter queues & parking integration - Enhanced scheduler to support synchronous I/O blocking - Comprehensive test suites for I/O (epoll) and mutex behavior - Documentation: LOOM.md concurrency model & README
77 lines
2.9 KiB
Rust
77 lines
2.9 KiB
Rust
//! # 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<Signal>`. Synchronisation primitives — `Mutex<T>` 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()
|
|
};
|
|
}
|