From b1240217bd003f01c5d382ab1812773c08afd8b6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 5 Aug 2021 22:24:03 +0200 Subject: [PATCH] Remove Portal. Fixes #32 Portal is very niche, I've only ever used it in `nrf-softdevice` and in a very particular case: sending event raw-pointers across tasks but "synchronously", because the destination task must process it now, so it's not deallocated. For most usecases, Signal or channels is enough. It's unclear to me whether it can be made ub-free. It has problems with reentrancy. It's also not leak-safe, which is quite annoying. So, remove it for now. We can always add it back later. --- embassy/src/util/mod.rs | 2 - embassy/src/util/portal.rs | 120 ------------------------------------- 2 files changed, 122 deletions(-) delete mode 100644 embassy/src/util/portal.rs diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 87d313e2..e66576b3 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -3,7 +3,6 @@ mod drop_bomb; mod forever; mod mutex; mod on_drop; -mod portal; mod signal; #[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")] @@ -14,7 +13,6 @@ pub use forever::*; pub mod mpsc; pub use mutex::*; pub use on_drop::*; -pub use portal::*; pub use signal::*; pub use waker::*; diff --git a/embassy/src/util/portal.rs b/embassy/src/util/portal.rs deleted file mode 100644 index 8ea48109..00000000 --- a/embassy/src/util/portal.rs +++ /dev/null @@ -1,120 +0,0 @@ -use core::cell::UnsafeCell; -use core::mem; -use core::mem::MaybeUninit; - -use crate::util::*; - -/// Utility to call a closure across tasks. -pub struct Portal { - state: UnsafeCell>, -} - -enum State { - None, - Running, - Waiting(*mut dyn FnMut(T)), -} - -impl Portal { - pub const fn new() -> Self { - Self { - state: UnsafeCell::new(State::None), - } - } - - pub fn call(&self, val: T) { - unsafe { - match *self.state.get() { - State::None => {} - State::Running => panic!("Portall::call() called reentrantly"), - State::Waiting(func) => (*func)(val), - } - } - } - - pub async fn wait_once<'a, R, F>(&'a self, mut func: F) -> R - where - F: FnMut(T) -> R + 'a, - { - let bomb = DropBomb::new(); - - let signal = Signal::new(); - let mut result: MaybeUninit = MaybeUninit::uninit(); - let mut call_func = |val: T| { - unsafe { - let state = &mut *self.state.get(); - *state = State::None; - result.as_mut_ptr().write(func(val)) - }; - signal.signal(()); - }; - - let func_ptr: *mut dyn FnMut(T) = &mut call_func as _; - let func_ptr: *mut dyn FnMut(T) = unsafe { mem::transmute(func_ptr) }; - - unsafe { - let state = &mut *self.state.get(); - match state { - State::None => {} - _ => panic!("Multiple tasks waiting on same portal"), - } - *state = State::Waiting(func_ptr); - } - - signal.wait().await; - - bomb.defuse(); - - unsafe { result.assume_init() } - } - - pub async fn wait_many<'a, R, F>(&'a self, mut func: F) -> R - where - F: FnMut(T) -> Option + 'a, - { - let bomb = DropBomb::new(); - - let signal = Signal::new(); - let mut result: MaybeUninit = MaybeUninit::uninit(); - let mut call_func = |val: T| { - unsafe { - let state = &mut *self.state.get(); - - let func_ptr = match *state { - State::Waiting(p) => p, - _ => unreachable!(), - }; - - // Set state to Running while running the function to avoid reentrancy. - *state = State::Running; - - *state = match func(val) { - None => State::Waiting(func_ptr), - Some(res) => { - result.as_mut_ptr().write(res); - signal.signal(()); - State::None - } - }; - }; - }; - - let func_ptr: *mut dyn FnMut(T) = &mut call_func as _; - let func_ptr: *mut dyn FnMut(T) = unsafe { mem::transmute(func_ptr) }; - - unsafe { - let state = &mut *self.state.get(); - match *state { - State::None => {} - _ => panic!("Multiple tasks waiting on same portal"), - } - *state = State::Waiting(func_ptr); - } - - signal.wait().await; - - bomb.defuse(); - - unsafe { result.assume_init() } - } -}