yot-run
A custom async runtime implementation demonstrating the core components of an async executor. yot-run is an educational project that provides a lightweight executor for running async tasks with support for spawning futures, managing their lifecycle, and integrating with OS-level I/O events.
Overview
yot-run implements a complete async runtime from the ground up, including:
- Executor: A work-stealing task scheduler with multiple worker threads
- Reactor: OS-backed event notification (epoll/kqueue) for async I/O
- Task Management: Thread-safe task lifecycle tracking using atomic operations
- Waker System: Custom waker implementations for task scheduling and thread unparking
- Networking: Async TCP primitives (
TcpListener,TcpStream) built on top of the runtime
Features
- β¨ Work-stealing task scheduler - Efficient task distribution across worker threads
- π Multi-threaded executor - CPU-aware worker pool (capped at 10 workers)
- π Non-blocking scheduling - Lock-free coordination using atomic operations
- π΄ OS-backed parking - Idle threads sleep without busy-waiting
- π Reactor integration - Event-driven I/O with epoll/kqueue support
- π Metrics tracking - Built-in Prometheus metrics (optional)
- π― Macro support -
#[yot_run::main]attribute for easy setup
Architecture
Core Components
βββββββββββββββββββββββββββββββββββββββββββ
β Runtime (main coordinator) β
βββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ ββββββββββββββββ β
β β Executor β β Reactor β β
β β β β β β
β β βββββββββββ β β ββββββββββββ β β
β β β Worker1 β β β β epoll/ β β β
β β β Worker2 β β β β loop β β β
β β β Worker3 β β β β β β β
β β βββββββββββ β β ββββββββββββ β β
β β β β β β
β βββββββββββββββ ββββββββββββββββ β
β β² β² β
β βββββββββββββββββββββββ β
β Task queues & wakers β
βββββββββββββββββββββββββββββββββββββββββββ
Runtime: Coordinates executor and reactor threads, stored in thread-local storage for easy access
Executor: Manages a pool of worker threads that steal tasks from a global injector queue and from each other's local queues
Reactor: Runs in a background thread monitoring OS I/O events, wakes tasks when data is ready
Tasks: Pinned futures with atomic state tracking (idle/polling/completed)
Wakers: Two implementationsβtask wakers re-enqueue into executor, unpark wakers wake threads
Module Structure
yot_run/
βββ executor/ # Task scheduling and worker threads
β βββ mod.rs # ExecutorHandle and Executor
β βββ worker.rs # Worker thread implementation
βββ reactor/ # I/O event handling
β βββ mod.rs # Reactor module definition
β βββ reactor.rs # Poll loop and event management
βββ lib.rs # Crate documentation and exports
βββ runtime.rs # Runtime orchestration
βββ task.rs # Task definition and lifecycle
βββ waker.rs # Waker implementations
βββ net.rs # Async TCP primitives
Quick Start
Basic Setup
async
The #[yot_run::main] macro automatically:
- Initializes the runtime
- Sets up executor and reactor threads
- Executes your async code within the runtime context
Spawning Tasks
async
Async I/O
use yot_run;
use TcpListener;
async
Disable Metrics
By default, the runtime starts a Prometheus metrics exporter on port 9000. To disable:
async
Building & Running
Build the project:
Build documentation:
Run tests:
How It Works
Task Execution Flow
- Spawn: Task created and enqueued to executor's injector queue
- Worker Processing: Worker polls local queue, then global injector, then steals from others
- Polling: Future advanced via
poll()within waker context - Pending: If future returns
Poll::Pending, task returned to queue with stored future - Ready: If future returns
Poll::Ready, task marked as completed
I/O Readiness Flow
- Register: Socket registered with reactor via
mio, assigned a token - Block: OS blocks in
poll()waiting for events - Event: OS signals data ready for socket
- Wake: Reactor looks up waker for token and calls
wake() - Resume: Task re-enqueued and resumed by worker
Synchronous Blocking
block_on() parks the current thread and uses an "unpark waker" that unblocks it when the future completes, allowing synchronous code to wait for async operations.
Metrics
When enabled (show_ui = true), metrics are available at http://localhost:9000/metrics:
yot_run_tasks_spawned_total- Total tasks spawnedyot_run_tasks_pending_current- Currently pending tasksyot_run_injector_depth- Tasks in global queueyot_run_worker_saturation_events_total- Times all workers were busyyot_run_worker_unparks_total- Worker wake events by thread
Contributing
Contributions, bug reports, and improvements are welcome β open an issue or submit a pull request.
License
See Cargo.toml for project metadata.
Educational Purpose
This project is designed to teach and demonstrate:
- How async executors work internally
- Work-stealing scheduling algorithms
- Thread synchronization with atomic operations
- OS-level I/O event handling with epoll/kqueue
- Waker-based task notification systems
- Thread parking for efficient idle waiting