diff --git a/CHANGELOG.md b/CHANGELOG.md index eb78d5d08f9..96cc88ac3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * CAN driver: support for pulling alerts in blocking and async mode * UART driver: support for pulling UART events * `task` and `interrupt` modules: new submodule in each - `asynch` - featuring a signal/notification-like synchronization primitive +* `task` module: `block_on` method capable of executing a future on the current thread * `task` module: new sub-module - `queue` for the FreeRTOS `queue` synchonization primitive * `task` module: new sub-module - `notification` - a more ergonomic API around the FreeRTOS task notification API which was already exposed via the `task::notify` and `task::wait_notification` APIs diff --git a/src/task.rs b/src/task.rs index dc88e335277..148b509debf 100644 --- a/src/task.rs +++ b/src/task.rs @@ -1,7 +1,10 @@ use core::cell::Cell; +use core::future::Future; use core::num::NonZeroU32; +use core::pin::pin; use core::ptr::{self, NonNull}; use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::{Context, Poll}; use esp_idf_sys::*; @@ -214,6 +217,33 @@ pub fn get_idle_task(core: crate::cpu::Core) -> TaskHandle_t { } } +/// Executes the supplied future on the current thread, thus blocking it until the future becomes ready. +pub fn block_on(mut fut: F) -> F::Output +where + F: Future, +{ + log::trace!("block_on(): started"); + + let notification = notification::Notification::new(); + + let mut fut = pin!(fut); + + let waker = notification.notifier().into(); + + let mut cx = Context::from_waker(&waker); + + let res = loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(res) => break res, + Poll::Pending => notification.wait_any(), + } + }; + + log::trace!("block_on(): finished"); + + res +} + #[cfg(esp_idf_comp_pthread_enabled)] pub mod thread { use core::ffi::CStr;