twizzler_async/lib.rs
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
//! Support for asynchronous programming on Twizzler. This crate provides executor functionality
//! along with support for async events and waiting, timers and timeouts, and a couple general
//! helper functions.
//!
//! # Executors
//! We provide three types of executors:
//! 1. block_on, which blocks until the future is completed.
//! 2. Thread-local, for futures that aren't Send.
//! 3. Global, which puts tasks in a global scheduling context for thread pools to handle.
//!
//! # Examples
//! The most basic way to run a future is:
//! ```
//! let result = block_on(async { /* some async code */ });
//! ```
//!
//! But this of course doesn't really make it possible to actually run things concurrently, since it
//! just waits for this single future. Instead, you probably want to use a real executor. The main
//! one you probably want is the global executor:
//! ```
//! let result = Task::spawn(async { /* some async code */ }).await;
//! ```
//! Now, this does assume that there is a thread that has called [mod@run()], eg:
//! ```
//! let result = run(async {
//! Task::spawn(async { /* some async code */ }).await
//! });
//! ```
//!
//! Generally, though, if you want a thread pool, you can spawn a thread into a pool like this:
//! ```
//! std::thread::spawn(|| twizzler_async::run(std::future::pending::<()>()));
//! ```
//!
//! Then, later on, you can spawn a Task and await it. You can also detach a Task with .detach(),
//! which just places the thread on the runqueues and runs it without you having to await the
//! result.
//!
//! # AsyncSetup, and Async<T>
//! Traits and types for asynchronous operations on objects that have generic wait and signal
//! events.
//!
//! For example, a queue might have the following interface presented to the user:
//! 1. `async fn send(T)`
//! 2. `async fn recv() -> T`
//!
//! Making these functions async requires defining some Future that can wait and be signaled when
//! something happens -- say we send and want to wait if the queue is full, or recv and want to wait
//! if the queue is empty, and of course we don't want to busy-wait. The queue can implement
//! [AsyncDuplexSetup] so that we can wrap the queue in a [AsyncDuplex] and then use its functions
//! to access the queue's underlying structures in a non-blocking way, automatically sleeping when
//! necessary.
mod async_source;
mod block_on;
mod event;
mod exec;
mod future;
mod reactor;
mod run;
mod task;
mod thread_local;
mod throttle;
mod timer;
pub use async_source::{Async, AsyncDuplex, AsyncDuplexSetup, AsyncSetup};
pub use future::{timeout_after, timeout_at, wait_for_first, FlagBlock};
pub use run::run;
pub use task::Task;
pub use timer::Timer;
pub use self::block_on::block_on;