use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::thread;
use napi::threadsafe_function::ThreadsafeFunction;
use napi::threadsafe_function::ThreadsafeFunctionCallMode;
use once_cell::unsync::Lazy;
use super::executor::wait_for_wake;
use super::executor::ThreadNotify;
use super::executor::ThreadNotifyRef;
thread_local! {
static WAKER_THREAD: Lazy<Sender<WakerEvent>> = Lazy::new(LocalWaker::start_waker_thread);
}
pub type WakerInit = ThreadsafeFunction<ThreadNotifyRef>;
pub enum WakerEvent {
Init(WakerInit),
Next,
Done,
}
pub struct LocalWaker;
impl LocalWaker {
pub fn send(event: WakerEvent) {
WAKER_THREAD
.with(|tx| tx.send(event))
.expect("Unable to communicate with waker");
}
fn start_waker_thread() -> Sender<WakerEvent> {
let (tx, rx) = channel();
thread::spawn(move || {
let thread_notify = ThreadNotify::new();
let mut handle = None::<WakerInit>;
while let Ok(event) = rx.recv() {
match event {
WakerEvent::Init(incoming) => {
if handle.replace(incoming).is_some() {
panic!("Handle already init");
};
let Some(ref handle) = handle else {
panic!("No handle");
};
handle.call(
Ok(thread_notify.clone()),
ThreadsafeFunctionCallMode::Blocking,
);
}
WakerEvent::Next => {
wait_for_wake(&thread_notify);
let Some(ref handle) = handle else {
panic!("No handle");
};
handle.call(
Ok(thread_notify.clone()),
ThreadsafeFunctionCallMode::Blocking,
);
}
WakerEvent::Done => {
if let Some(handle) = handle.take() {
drop(handle);
}
}
};
}
});
tx
}
}