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.
This commit is contained in:
Dario Nieuwenhuis 2021-08-05 22:24:03 +02:00
parent 8a65128cfe
commit b1240217bd
2 changed files with 0 additions and 122 deletions

View file

@ -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::*;

View file

@ -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<T> {
state: UnsafeCell<State<T>>,
}
enum State<T> {
None,
Running,
Waiting(*mut dyn FnMut(T)),
}
impl<T> Portal<T> {
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<R> = 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<R> + 'a,
{
let bomb = DropBomb::new();
let signal = Signal::new();
let mut result: MaybeUninit<R> = 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() }
}
}