Skip to content

Commit

Permalink
runtime: handle missing context on wake (#6148)
Browse files Browse the repository at this point in the history
  • Loading branch information
Darksonn committed Nov 14, 2023
1 parent 49eb26f commit 2e5773a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
4 changes: 3 additions & 1 deletion tokio/src/runtime/context.rs
Expand Up @@ -178,7 +178,9 @@ cfg_rt! {

#[track_caller]
pub(super) fn with_scheduler<R>(f: impl FnOnce(Option<&scheduler::Context>) -> R) -> R {
CONTEXT.with(|c| c.scheduler.with(f))
let mut f = Some(f);
CONTEXT.try_with(|c| c.scheduler.with(f.take().unwrap()))
.unwrap_or_else(|_| (f.take().unwrap())(None))
}

cfg_taskdump! {
Expand Down
62 changes: 62 additions & 0 deletions tokio/tests/rt_common.rs
Expand Up @@ -1366,4 +1366,66 @@ rt_test! {
th.join().unwrap();
}
}

#[test]
#[cfg_attr(target_family = "wasm", ignore)]
fn wake_by_ref_from_thread_local() {
wake_from_thread_local(true);
}

#[test]
#[cfg_attr(target_family = "wasm", ignore)]
fn wake_by_val_from_thread_local() {
wake_from_thread_local(false);
}

fn wake_from_thread_local(by_ref: bool) {
use std::cell::RefCell;
use std::sync::mpsc::{channel, Sender};
use std::task::Waker;

struct TLData {
by_ref: bool,
waker: Option<Waker>,
done: Sender<bool>,
}

impl Drop for TLData {
fn drop(&mut self) {
if self.by_ref {
self.waker.take().unwrap().wake_by_ref();
} else {
self.waker.take().unwrap().wake();
}
let _ = self.done.send(true);
}
}

std::thread_local! {
static TL_DATA: RefCell<Option<TLData>> = RefCell::new(None);
};

let (send, recv) = channel();

std::thread::spawn(move || {
let rt = rt();
rt.block_on(rt.spawn(poll_fn(move |cx| {
let waker = cx.waker().clone();
let send = send.clone();
TL_DATA.with(|tl| {
tl.replace(Some(TLData {
by_ref,
waker: Some(waker),
done: send,
}));
});
Poll::Ready(())
})))
.unwrap();
})
.join()
.unwrap();

assert!(recv.recv().unwrap());
}
}

0 comments on commit 2e5773a

Please sign in to comment.