uefi_async/lib.rs
1//!uefi-async
2//! ================================
3//! A lightweight, zero-cost asynchronous executor designed specifically for UEFI environments or bare-metal Rust. It provides a simple task scheduler based on a intrusive linked-list and a procedural macro to simplify task registration.
4//!
5//! WIP
6//! --------------------------------
7//! currently only `nano_alloc` feature is supported.
8//!
9//! Features
10//! --------------------------------
11//! * **No-Std Compatible**: Designed for environments without a standard library (only requires `alloc`).
12//! * **Intrusive Linked-List**: No additional collection overhead for managing tasks.
13//! * **Frequency-Based Scheduling**: Define tasks to run at specific frequencies (Hz), automatically converted to hardware ticks.
14//! * **Macro-Driven Syntax**: A clean, declarative DSL to assign tasks to executors.
15//!
16//! Architecture
17//! --------------------------------
18//! The project consists of two main components:
19//!
20//! 1. **The Executor**: A round-robin scheduler that polls `TaskNode`s based on timing requirements.
21//! 2. **The Task Macro**: A procedural macro that handles the boilerplate of pinning futures and registering them to executors.
22//!
23//! Installation
24//! --------------------------------
25//! Add this to your `Cargo.toml`:
26//!
27//! ```toml
28//! [dependencies]
29//! uefi-async = "*"
30//!
31//! ```
32//!
33//! Usage
34//! --------------------------------
35//!
36//! ### 1. Define your tasks
37//!
38//! Tasks are standard Rust `async` functions or closures.
39//!
40//! ### 2. Initialize and Run
41//!
42//! Use the `add!` macro to set up your executor.
43//!
44//! ```rust
45//! extern crate alloc;
46//! use alloc::boxed::Box;
47//! use uefi_async::nano_alloc::{Executor, TaskNode};
48//!
49//! async fn calc_1() {}
50//! async fn calc_2() {}
51//!
52//! extern "efiapi" fn process(arg: *mut c_void) {
53//! // 1. Create executor
54//! Executor::new()
55//! // 2. Register tasks
56//! .add(&mut TaskNode::new(Box::pin(calc_1()), 0))
57//! .add(&mut TaskNode::new(Box::pin(calc_2()), 60))
58//! // 3. Run the event loop
59//! .run_forever();
60//! }
61//! ```
62//!
63//! or more advanced usage:
64//!
65//!```rust
66//! extern crate alloc;
67//! use uefi_async::nano_alloc::{Executor, add};
68//! use uefi_async::common::tick;
69//!
70//! async fn af1() {}
71//! async fn af2(_: usize) {}
72//! async fn af3(_: usize, _:usize) {}
73//!
74//! extern "efiapi" fn process(arg: *mut c_void) {
75//! if arg.is_null() { return }
76//! let ctx = unsafe { &mut *arg.cast::<Context>() };
77//! let core = ctx.mp.who_am_i().expect("Failed to get core ID");
78//!
79//! // 1. Create executor
80//! let mut executor1 = Executor::new();
81//! let mut executor2 = Executor::new();
82//! let mut cx = Executor::init_step();
83//!
84//! let offset = 20;
85//! // 2. Use the macro to register tasks
86//! // Syntax: executor => { frequency -> future }
87//! add! (
88//! executor1 => {
89//! 0 -> af1(), // Runs at every tick
90//! 60 -> af2(core), // Runs at 60 HZ
91//! },
92//! executor2 => {
93//! 10u64.saturating_sub(offset) -> af3(core, core),
94//! 30 + 10 -> af1(),
95//! },
96//! );
97//!
98//! loop {
99//! calc_sync(core);
100//!
101//! // 3. Run the event loop manually
102//! executor1.run_step(tick(), &mut cx);
103//! executor2.run_step(tick(), &mut cx);
104//! }
105//! }
106//! ```
107//!
108//! Why use `uefi-async`?
109//! --------------------------------
110//! In UEFI development, managing multiple periodic tasks (like polling keyboard input while updating a UI or handling network packets) manually can lead to "spaghetti code." `uefi-async` allows you to write clean, linear `async/await` code while the executor ensures that timing constraints are met without a heavy OS-like scheduler.
111//!
112//! License
113//! --------------------------------
114//! This project is licensed under the MIT License or Apache-2.0. (temporary)
115
116#![warn(unreachable_pub)]
117#![no_std]
118#![cfg_attr(docsrs, feature(doc_cfg))]
119
120#[cfg(any(feature = "nano-alloc", feature = "alloc"))]
121extern crate alloc;
122
123/// Utility functions for hardware timing and platform-specific operations.
124///
125/// Includes the TSC-based tick counter and frequency calibration.
126pub mod common;
127pub use common::*;
128
129/// Static task management module.
130///
131/// This module provides a mechanism for running the executor without
132/// a dynamic memory allocator, utilizing static memory or stack-allocated
133/// task nodes. Useful for highly constrained environments.
134#[cfg(feature = "static")]
135pub mod no_alloc;
136
137/// Standard asynchronous executor implementation using `alloc`.
138///
139/// Provides the Executor and TaskNode types that rely on
140/// `Box` and `Pin` for flexible task management.
141/// Requires a global allocator to be defined.
142#[cfg(feature = "alloc")]
143pub mod dynamic;
144
145/// Helper module for setting up a global allocator in UEFI.
146///
147/// When enabled, this module provides a bridge between the Rust
148/// memory allocation API and the UEFI Boot Services memory allocation functions.
149#[cfg(feature = "global-allocator")]
150pub mod global_allocator;
151
152/// Specialized, lightweight memory allocator for constrained systems.
153///
154/// A minimal allocator implementation designed to have a very small
155/// footprint, specifically optimized for managing asynchronous task nodes.
156#[cfg(feature = "nano-alloc")]
157pub mod nano_alloc;