pub struct CountingThreadScope<'env, 'id> {
threads: u16,
_phantom: PhantomData<(&'env (), &'id ())>,
}
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 thescope()
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.
Fields§
§threads: u16
§_phantom: PhantomData<(&'env (), &'id ())>
Implementations§
Source§impl<'env, 'id> CountingThreadScope<'env, 'id>
impl<'env, 'id> CountingThreadScope<'env, 'id>
Sourcepub 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>
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>
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.
Sourcepub fn reap(&mut self, thread: CountedThread<'id>)
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.
fn wait_for_all(self)
Auto Trait Implementations§
impl<'env, 'id> Freeze for CountingThreadScope<'env, 'id>
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoSwitch for T
impl<T> IntoSwitch for T
Source§fn into_switch<ActiveLevel>(self) -> Switch<T, ActiveLevel>
fn into_switch<ActiveLevel>(self) -> Switch<T, ActiveLevel>
Source§fn into_active_high_switch(self) -> Switch<Self, ActiveHigh>where
Self: Sized,
fn into_active_high_switch(self) -> Switch<Self, ActiveHigh>where
Self: Sized,
Layout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...)
attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 2 bytes