Skip to content

Commit bed615d

Browse files
committed
fix(any_spawner): use spawner handle
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 <[email protected]>
1 parent 7aaddb0 commit bed615d

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

any_spawner/src/lib.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -261,36 +261,53 @@ impl Executor {
261261
pub fn init_futures_local_executor() -> Result<(), ExecutorError> {
262262
use std::cell::RefCell;
263263

264-
use futures::{executor::LocalPool, task::LocalSpawnExt};
264+
use futures::{
265+
executor::{LocalPool, LocalSpawner},
266+
task::LocalSpawnExt,
267+
};
265268

266269
thread_local! {
267270
static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
271+
static SPAWNER_HANDLE: OnceLock<LocalSpawner> = OnceLock::new();
268272
}
269273

274+
SPAWNER_HANDLE.with(|spawner_handle| {
275+
LOCAL_POOL.with(|local_pool| {
276+
spawner_handle
277+
.set(local_pool.borrow().spawner())
278+
.expect("unexpected error when getting executor spawner");
279+
});
280+
});
281+
270282
SPAWN
271283
.set(|fut| {
272-
LOCAL_POOL.with(|pool| {
273-
let spawner = pool.borrow().spawner();
274-
spawner.spawn_local(fut).expect("failed to spawn future");
284+
SPAWNER_HANDLE.with(|spawner| {
285+
spawner
286+
.get()
287+
.expect("executor spawner was not set")
288+
.spawn_local(fut)
289+
.expect("failed to spawn future");
275290
});
276291
})
277292
.map_err(|_| ExecutorError::AlreadySet)?;
278293
SPAWN_LOCAL
279294
.set(|fut| {
280-
LOCAL_POOL.with(|pool| {
281-
let spawner = pool.borrow().spawner();
282-
spawner.spawn_local(fut).expect("failed to spawn future");
295+
SPAWNER_HANDLE.with(|spawner| {
296+
spawner
297+
.get()
298+
.expect("executor spawner was not set")
299+
.spawn_local(fut)
300+
.expect("failed to spawn future");
283301
});
284302
})
285303
.map_err(|_| ExecutorError::AlreadySet)?;
286304

287-
RUN
288-
.set(|| {
289-
LOCAL_POOL.with(|pool| {
290-
pool.borrow_mut().run();
291-
});
292-
})
293-
.map_err(|_| ExecutorError::AlreadySet)?;
305+
RUN.set(|| {
306+
LOCAL_POOL.with(|pool| {
307+
pool.borrow_mut().run();
308+
});
309+
})
310+
.map_err(|_| ExecutorError::AlreadySet)?;
294311

295312
Ok(())
296313
}

0 commit comments

Comments
 (0)