#[allow(unused_imports)]
use crate::mwpf::shim::prelude::*;
use pyo3::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::{sleep, spawn, JoinHandle};
use std::time::Duration;
pub fn force_check_signals() -> PyResult<()> {
Python::attach(|py| py.check_signals())
}
pub struct PythonSignalChecker {
pub should_check: &'static AtomicBool,
pub is_skipping_next: &'static AtomicBool,
pub thread_handler: JoinHandle<()>,
}
pub static DEFAULT_SHOULD_CHECK: AtomicBool = AtomicBool::new(false);
pub static DEFAULT_IS_SKIPPING_NEXT: AtomicBool = AtomicBool::new(false);
pub static DEFAULT_SLEEP_INTERVAL_MILLIS: u64 = 100;
pub static PYTHON_SIGNAL_CHECKER: std::sync::LazyLock<PythonSignalChecker> = std::sync::LazyLock::new(|| {
PythonSignalChecker::new(&DEFAULT_SHOULD_CHECK, &DEFAULT_IS_SKIPPING_NEXT, DEFAULT_SLEEP_INTERVAL_MILLIS)
});
impl PythonSignalChecker {
pub fn new(
should_check: &'static AtomicBool,
is_skipping_next: &'static AtomicBool,
sleep_interval_millis: u64,
) -> Self {
let thread_handler = spawn(move || {
loop {
if is_skipping_next.swap(false, Ordering::Relaxed) {
continue;
}
should_check.store(true, Ordering::Relaxed);
sleep(Duration::from_millis(sleep_interval_millis));
}
});
Self {
should_check,
is_skipping_next,
thread_handler,
}
}
#[inline]
pub fn check(&self) -> PyResult<()> {
if self.should_check.swap(false, Ordering::Relaxed) {
force_check_signals()?;
}
Ok(())
}
#[inline]
pub fn skip_next(&self) {
self.is_skipping_next.store(true, Ordering::Relaxed);
self.should_check.store(false, Ordering::Relaxed);
}
}