Skip to content

cold futures: speaker note - #401

Open
robamu wants to merge 1 commit into
mainfrom
futures-might-not-be-cold
Open

robamu wants to merge 1 commit into
mainfrom
futures-might-not-be-cold

Conversation

@robamu

@robamu robamu commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

In the embedded contexts, we can have futures that already start part of the work (e.g. UART transmission futures which loads the FIFO with the initial bytes). So those are not really "cold", or at the very least I think calling them "cold" is confusing.

Maybe we can just remove this? I think the knowledge that futures need to be executed/resolved is sufficient.

@robamu robamu changed the title futures might not always be completely cold futures might not always be cold Jul 22, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploying ferrous-systems-rust-training with  Cloudflare Pages  Cloudflare Pages

Latest commit: 37f9357
Status: ✅  Deploy successful!
Preview URL: https://0c69eb7f.ferrous-systems-rust-training.pages.dev
Branch Preview URL: https://futures-might-not-be-cold.ferrous-systems-rust-training.pages.dev

View logs

@robamu

robamu commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

replaced by speaker note to clarify that some work might already start during the future construction

@robamu
robamu requested review from listochkin and skade July 27, 2026 10:07
@robamu robamu changed the title futures might not always be cold cold futures: speaker note Jul 27, 2026
Note:

* While the future itself might be cold, its construction might already start or do some of
the work related to the future.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the future is creates using async then you can't do any custom work in the constructor.

If you make a future manually (using implementation Future for StructType or poll_fn), then you can customize the behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was a nod towards:

fn do_process() -> impl Future<Foo> {
    hal::start_dma();
    async {
        hal::wait_dma().await
    }
}

Where a sync function both does some work, and returns a future that must be polled. I don't know how often this comes up in practice.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also

impl<'uart> Transmission<'uart> {
/// Create a new asynchronous future for a write/transmit operation.
///
/// Will send the given buffer under interrupt, producing
/// `core::task::Poll::Ready` once complete.
///
/// Do not pass a zero-length slice - this will panic.
///
/// We can only keep this object whilst *both* the Async TX UART *and* the buffer are alive.
fn new(tx_async: &'uart mut AsyncTx, data: &'uart [u8]) -> Self {
defmt::debug!(
"Creating Transmission(data=0x{=usize:08x}, len={})",
data.as_ptr() as usize,
data.len(),
);
assert!(!data.is_empty());
// tx.inner.disable_interrupts();
tx_async.uart_state.tx_length.store(data.len(), Relaxed);
tx_async.uart_state.tx_transmitted.store(1, Relaxed);
tx_async
.uart_state
.tx_buffer
.store(data.as_ptr() as *mut u8, Release);
// It is actually important to write AFTER the UART was enabled.
defmt::debug!("TX 0x{:02x}", data[0]);
tx_async.basic_tx.write(data[0]).unwrap();
Self { tx: tx_async }
}
}
impl core::future::Future for Transmission<'_> {
type Output = ();
fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
defmt::debug!("Polling Transmission complete...");
self.tx.uart_state.waker.register(cx.waker());
if self.tx.uart_state.tx_buffer.load(Acquire).is_null() {
defmt::debug!("Ready!");
core::task::Poll::Ready(())
} else {
defmt::debug!("Pending...");
core::task::Poll::Pending
}
}
}
impl Drop for Transmission<'_> {
fn drop(&mut self) {
if !self.tx.uart_state.tx_buffer.load(Acquire).is_null() {
self.tx.basic_tx.clear_interrupts();
self.tx.basic_tx.enable_interrupt(false);
}
}
}
, where we impl Future for CustomType to get Drop behaviour for the Future.

@robamu
robamu force-pushed the futures-might-not-be-cold branch from 0c794c4 to d3ffe7b Compare September 1, 2026 14:12
@robamu
robamu requested a review from listochkin September 1, 2026 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants