Search code examples
rustrust-tokio

Other than calling `waker.wake()` how can I make sure the Future will be polled again?


I'm looking into some more complex Rust projects and I noticed that a lot of them instead of using only async functions implement Future manually to get greater control of what happens.

The problem is that in the entire project, there is no call to waker.wake() whatsoever, so I have no idea how they make sure the future is polled again.

Let's say I want to poll an endless Future that always returns Poll::Pending but without calling waker.wake(). What are the other options?

Also, any resources on this topic and async rust are appreciated.

Thanks!


Solution

  • Using the Waker provided by the Context is the only way (in general) for a Future implementation to communicate to its executor - which is to indicate that the task associated with that waker should be polled again such that progress can be made.

    Making use of the Waker yourself is not very common since it can only be used effectively by Futures that have a out-of-band method to know that a value or signal being waited on is ready. This is usually restricted to low-level I/O operations, timers, other triggers from the OS, and notifications from other tasks or threads. If you are making your own Future that relies on other Futures, you won't use the waker yourself and simply pass the context when polling the inner Future.

    When you use an async block or function, the state-machine type that is built by the compiler will implement Future with a poll function that defers to the current Future being .await-ed by simply passing the context. So its only the lowest, deepest Future that would actually use the waker.

    That all being said, there are no guarantees. Your Future may be poll-ed without calling the waker; this can happen if your task is using something like select! elsewhere which is managing multiple Futures in the same task. You may also call .wake() on your waker but the executor is totally free to ignore it, or it may be stuck, or shutting down, or whatever else. In the most likely case, things will work as you'd expect but edge cases always exist.

    This section of the Asynchronous Programming in Rust looks relevant: Under the Hood: Executing Futures and Tasks. If you are looking for a non-runtime specific implementation that uses the waker (since those may be very complicated underneath), you can look at futures::channel::oneshot::Sender.

    As a side note, a Future that always returns Poll::Pending is already in the standard library - std::future::pending - but of course, it doesn't call the waker (since why would it if it is only always going to be pending?).