pub struct CountingThreadScope<'env, 'id> { /* private fields */ }
Expand description

Lifetimed helper through which threads can be spawned.

§Lifetimes

The involved lifetimes ensure that all parts used to build the thread (its closure, stack, and name) outlive the whole process, which (given the generally dynamic lifetime of threads) can only be checked dynamically.

The lifetimes are:

  • 'env: A time surrounding the scope() call. All inputs to the thread are checked to live at least that long (possibly longer; it is commonplace for them to be 'static).

  • 'id: An identifying lifetime (or brand) of the scope. Its lifetime is somewhere inbetween the outer 'env and the run time of the called closure.

    Practically, don’t think of this as a lifetime, but more as a disambiguator: It makes the monomorphized CountingThreadScope unique in the sense that no two instances of CountingThreadScope can ever have the same type.

    By having unique types, it is ensured that a counted thread is only counted down (in [.reap()]) in the scope it was born in, and that no shenanigans with counters being swapped around with core::mem::swap() are used to trick the compiler into allowing use-after-free.

This technique was inspired by (and is explained well) in the GhostCell Paper.

Implementations§

source§

impl<'env, 'id> CountingThreadScope<'env, 'id>

source

pub fn spawn<R>( &mut self, stack: &'env mut [u8], closure: &'env mut R, name: &'env CStr, priority: u8, flags: i32 ) -> Result<CountedThread<'id>, kernel_pid_t>
where R: Send + FnMut(),

Start a thread in the given stack, in which the closure is run. The thread gets a human readable name (ignored in no-DEVHELP mode), and is started with the priority and flags as per thread_create documentation.

The returned thread object can safely be discarded when the scope is not expected to ever return, and needs to be passed on to .reap() otherwise.

Having the closure as a mutable reference (rather than a moved instance) is a bit unergonomic as it means that spawn(..., || { foo }, ..) one-line invocations are impossible, but is necessary as it avoids having the callback sitting in the Thread which can’t be prevented from moving around on the stack between the point when thread_create is called (and the pointer is passed on to RIOT) and the point when the threads starts running and that pointer is used.

source

pub fn reap(&mut self, thread: CountedThread<'id>)

Assert that the thread has terminated, and remove it from the list of pending threads in this context.

Unlike a (POSIX) wait, this will not block (for there is no SIGCHLDish thing in RIOT – whoever wants to be notified would need to make their threads send an explicit signal), but panic if the thread is not actually done yet.

Auto Trait Implementations§

§

impl<'env, 'id> RefUnwindSafe for CountingThreadScope<'env, 'id>

§

impl<'env, 'id> Send for CountingThreadScope<'env, 'id>

§

impl<'env, 'id> Sync for CountingThreadScope<'env, 'id>

§

impl<'env, 'id> Unpin for CountingThreadScope<'env, 'id>

§

impl<'env, 'id> UnwindSafe for CountingThreadScope<'env, 'id>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoSwitch for T

source§

fn into_switch<ActiveLevel>(self) -> Switch<T, ActiveLevel>

Consumes the IoPin returning a Switch of the appropriate ActiveLevel. Read more
source§

fn into_active_low_switch(self) -> Switch<Self, ActiveLow>
where Self: Sized,

Consumes the IoPin returning a Switch<IoPin, ActiveLow>. Read more
source§

fn into_active_high_switch(self) -> Switch<Self, ActiveHigh>
where Self: Sized,

Consumes the IoPin returning a Switch<IoPin, ActiveHigh>. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.