Skip to content

Commit

Permalink
fix(any_spawner): use spawner handle
Browse files Browse the repository at this point in the history
This commits fix a panic that could arrive because of
conflicting borrowing of the `LOCAL_POOL`.

When `.run()` is executed, it mut borrows the LocalPool
for the whole duration of the Task which means, any
call to `Executor::spawn` by ran Futures would make
the `RefCell` panics.

Signed-off-by: Enzo "raskyld" Nocera <enzo@nocera.eu>
  • Loading branch information
raskyld committed Oct 6, 2024
1 parent 7aaddb0 commit bed615d
Showing 1 changed file with 31 additions and 14 deletions.
45 changes: 31 additions & 14 deletions any_spawner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,36 +261,53 @@ impl Executor {
pub fn init_futures_local_executor() -> Result<(), ExecutorError> {
use std::cell::RefCell;

use futures::{executor::LocalPool, task::LocalSpawnExt};
use futures::{
executor::{LocalPool, LocalSpawner},
task::LocalSpawnExt,
};

thread_local! {
static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
static SPAWNER_HANDLE: OnceLock<LocalSpawner> = OnceLock::new();
}

SPAWNER_HANDLE.with(|spawner_handle| {
LOCAL_POOL.with(|local_pool| {
spawner_handle
.set(local_pool.borrow().spawner())
.expect("unexpected error when getting executor spawner");
});
});

SPAWN
.set(|fut| {
LOCAL_POOL.with(|pool| {
let spawner = pool.borrow().spawner();
spawner.spawn_local(fut).expect("failed to spawn future");
SPAWNER_HANDLE.with(|spawner| {
spawner
.get()
.expect("executor spawner was not set")
.spawn_local(fut)
.expect("failed to spawn future");
});
})
.map_err(|_| ExecutorError::AlreadySet)?;
SPAWN_LOCAL
.set(|fut| {
LOCAL_POOL.with(|pool| {
let spawner = pool.borrow().spawner();
spawner.spawn_local(fut).expect("failed to spawn future");
SPAWNER_HANDLE.with(|spawner| {
spawner
.get()
.expect("executor spawner was not set")
.spawn_local(fut)
.expect("failed to spawn future");
});
})
.map_err(|_| ExecutorError::AlreadySet)?;

RUN
.set(|| {
LOCAL_POOL.with(|pool| {
pool.borrow_mut().run();
});
})
.map_err(|_| ExecutorError::AlreadySet)?;
RUN.set(|| {
LOCAL_POOL.with(|pool| {
pool.borrow_mut().run();
});
})
.map_err(|_| ExecutorError::AlreadySet)?;

Ok(())
}
Expand Down

0 comments on commit bed615d

Please sign in to comment.