1 unstable release

0.1.0 Feb 28, 2021

MIT license

99KB
1K SLoC

exit-stack

Dynamically pin values to the stack.


lib.rs:

Dynamically pin values to the stack.

This is motivated by a short-coming of pinning in situations where no global allocator is available (or the use of one is not desired). The usual solution for pinning a value to the stack is by utilizing the pin_utils macro, which works by shadowing a value and thus making it impossible to avoid its Drop impl being run. However, by design this can only work if the number of values is statically known.

This crate complements the mechanism. It leverages a pinned wrapper around an area of memory to constructs a linked list of values that are dropped together with that region, and thus can be treated as pinned as well. The downside of this is a more imprecise tracking which requires the values themselves to live for the 'static lifetime by default.

Usage

Use this to have subroutines that starts some task that must be pinned while it is running. An example for this is a DMA transfer, that absolutely must signal or wait for the remote end when it is dropped (as otherwise some memory might get corrupted later). This would usually not be easily possible as stack-pinning the tasks within the subroutine would immediately drop them on exit.

use core::pin::Pin;
use exit_stack::ExitStack;

#[derive(Default)]
struct DmaTask {
    // ..
# _inner: (),
}

impl DmaTask {
    // Start a DMA transfer, return an identifier for it.
    pub fn start(self: Pin<&mut Self>) -> usize {
        // ..
# 0
    }
}

fn start_pinned(mut stack: Pin<&ExitStack<DmaTask>>) -> Option<usize> {
    let task = stack
        .slot()?
        .pin(DmaTask::default());
    Some(task.start())
}

Dependencies