use std::thread;
use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
#[derive(Debug)]
pub struct Flag {
alive: Arc<AtomicBool>,
interrupt: Arc<AtomicBool>,
}
impl Drop for Flag {
fn drop(&mut self) {
if thread::panicking() {
(*self.interrupt).store(true, Ordering::Relaxed)
}
}
}
impl Flag {
pub fn new() -> Self {
Flag {
alive: Arc::new(AtomicBool::new(true)),
interrupt: Arc::new(AtomicBool::new(false)),
}
}
pub fn take_control(&self) -> Control {
Control {
alive: Arc::downgrade(&self.alive),
interrupt: self.interrupt.clone(),
}
}
pub fn alive(&self) -> bool {
if (*self.interrupt).load(Ordering::Relaxed) {
panic!("thread interrupted by thread-contol");
}
(*self.alive).load(Ordering::Relaxed)
}
pub fn is_alive(&self) -> bool {
(*self.alive).load(Ordering::Relaxed) && !(*self.interrupt).load(Ordering::Relaxed)
}
pub fn interrupt(self) {
(self.interrupt).store(true, Ordering::Relaxed)
}
}
#[derive(Debug, Clone)]
pub struct Control {
alive: Weak<AtomicBool>,
interrupt: Arc<AtomicBool>,
}
impl Control {
pub fn interrupt(&self) {
(*self.interrupt).store(true, Ordering::Relaxed)
}
pub fn stop(&self) {
self.alive.upgrade().map(|flag| {
(*flag).store(false, Ordering::Relaxed)
});
}
pub fn is_done(&self) -> bool {
self.alive.upgrade().is_none()
}
pub fn is_interrupted(&self) -> bool {
(*self.interrupt).load(Ordering::Relaxed)
}
}
pub fn make_pair() -> (Flag, Control) {
let flag = Flag::new();
let control = flag.take_control();
(flag, control)
}