What the Rust language and standard library take care of 133 In step 3, when the reactor gets a notification that an event has happened on one of the tracked sources, it locates the Waker associated with that source and calls Waker::wake on it. This will in turn inform the executor that the future is ready to make progress so it can poll it once more. If we write a short async program using pseudocode, it will look like this: async fn foo() { println!("Start!"); let txt = io::read_to_string(). await. unwrap(); println!("{txt}"); } The line where we write await is the one that will return control back to the scheduler. This is often called a yield point since it will return either Poll::Pending or Poll::Ready (most likely it will return Poll::Pending the first time the future is polled). Since the Waker is the same across all executors, reactors can, in theory, be completely oblivious to the type of executor, and vice-versa. Executors and reactors never need to communicate with one another directly. This design is what gives the futures framework its power and flexibility and allows the Rust standard library to provide an ergonomic, zero-cost abstraction for us to use. Note I introduced the concept of reactors and executors here like it's something everyone knows about. I know that's not the case, and don't worry, we'll go through this in detail in the next chapter. What the Rust language and standard library take care of Rust only provides what's necessary to model asynchronous operations in the language. Basically, it provides the following: A common interface that represents an operation, which will be completed in the future through the Future trait An ergonomic way of creating tasks (stackless coroutines to be precise) that can be suspended and resumed through the async and await keywords A defined interface to wake up a suspended task through the Waker type That's really what Rust's standard library does. As you see there is no definition of non-blocking I/O, how these tasks are created, or how they're run. There is no non-blocking version of the standard library, so to actually run an asynchronous program, you have to either create or decide on a runtime to use.