use std::panic::catch_unwind;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread::spawn;
use crossbeam::channel::{self, SendError, Sender};
use parking_lot::RwLock;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
use crate::collector::GcData;
pub(crate) struct BackgroundDropper {
sender: Sender<DropMessage>,
}
pub(crate) enum DropMessage {
DataToDrop(RwLock<Vec<Arc<GcData>>>),
SyncUp(Sender<()>),
}
impl BackgroundDropper {
pub fn new() -> Self {
let (sender, receiver) = channel::unbounded();
spawn(move || {
while let Ok(drop_msg) = receiver.recv() {
match drop_msg {
DropMessage::DataToDrop(to_drop) => {
let to_drop = to_drop.read();
to_drop.par_iter().for_each(|data| {
data.deallocated.store(true, Ordering::SeqCst);
});
to_drop.par_iter().for_each(|data| {
let underlying_allocation = data.underlying_allocation;
let res = catch_unwind(move || unsafe {
underlying_allocation.deallocate();
});
if let Err(e) = res {
eprintln!("Gc background drop failed: {:?}", e);
}
});
}
DropMessage::SyncUp(responder) => {
if let Err(e) = responder.send(()) {
eprintln!("Gc background syncup failed: {:?}", e);
}
}
}
}
});
Self { sender }
}
pub fn send_msg(&self, msg: DropMessage) -> Result<(), SendError<DropMessage>> {
self.sender.send(msg)
}
}