Skip to content

Commit

Permalink
Fix #362
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmarkov committed Jan 26, 2024
1 parent 16a10d0 commit 5ed5d8a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
41 changes: 41 additions & 0 deletions src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::future::Future;
use core::num::NonZeroU32;
#[cfg(feature = "alloc")]
use core::pin::pin;
use core::pin::Pin;
use core::ptr::{self, NonNull};
use core::sync::atomic::{AtomicBool, Ordering};
#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -280,6 +281,46 @@ where
res
}

/// Yield from the current task once, allowing other tasks to run.
///
/// This can be used to easily and quickly implement simple async primitives
/// without using wakers. The following snippet will wait for a condition to
/// hold, while still allowing other tasks to run concurrently (not monopolizing
/// the executor thread).
///
/// ```rust,no_run
/// while !some_condition() {
/// yield_now().await;
/// }
/// ```
///
/// The downside is this will spin in a busy loop, using 100% of the CPU, while
/// using wakers correctly would allow the CPU to sleep while waiting.
///
/// The internal implementation is: on first poll the future wakes itself and
/// returns `Poll::Pending`. On second poll, it returns `Poll::Ready`.
pub fn yield_now() -> impl Future<Output = ()> {
YieldNowFuture { yielded: false }
}

#[must_use = "futures do nothing unless you `.await` or poll them"]
struct YieldNowFuture {
yielded: bool,
}

impl Future for YieldNowFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
}

#[cfg(esp_idf_comp_pthread_enabled)]
pub mod thread {
use core::ffi::CStr;
Expand Down
28 changes: 20 additions & 8 deletions src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1470,8 +1470,11 @@ where
_ => (),
}

let port = self.driver.borrow().port as usize;
WRITE_NOTIFS[port].wait().await;
// We cannot properly wait for the TX FIFO queue to become non-full
// because the ESP IDF UART ISR does not notify us on that
//
// Instead, spin a busy loop, however still allowing other futures to be polled too.
crate::task::yield_now().await;
}
}
}
Expand All @@ -1486,8 +1489,11 @@ where
_ => (),
}

let port = self.driver.borrow().port as usize;
TX_NOTIFS[port].wait().await;
// We cannot properly wait for the TX FIFO queue to become empty
// because the ESP IDF UART ISR does not notify us on that
//
// Instead, spin a busy loop, however still allowing other futures to be polled too.
crate::task::yield_now().await;
}
}
}
Expand Down Expand Up @@ -1704,8 +1710,11 @@ where
_ => (),
}

let port = self.driver.borrow().port as usize;
WRITE_NOTIFS[port].wait().await;
// We cannot properly wait for the TX FIFO queue to become non-full
// because the ESP IDF UART ISR does not notify us on that
//
// Instead, spin a busy loop, however still allowing other futures to be polled too.
crate::task::yield_now().await;
}
}
}
Expand All @@ -1720,8 +1729,11 @@ where
_ => (),
}

let port = self.driver.borrow().port as usize;
TX_NOTIFS[port].wait().await;
// We cannot properly wait for the TX FIFO queue to become empty
// because the ESP IDF UART ISR does not notify us on that
//
// Instead, spin a busy loop, however still allowing other futures to be polled too.
crate::task::yield_now().await;
}
}
}
Expand Down

0 comments on commit 5ed5d8a

Please sign in to comment.