use crate::vm::VMBinding;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Condvar, Mutex};
struct RequestSync {
request_count: isize,
last_request_count: isize,
}
pub struct GCRequester<VM: VMBinding> {
request_sync: Mutex<RequestSync>,
request_condvar: Condvar,
request_flag: AtomicBool,
phantom: PhantomData<VM>,
}
impl<VM: VMBinding> Default for GCRequester<VM> {
fn default() -> Self {
Self::new()
}
}
impl<VM: VMBinding> GCRequester<VM> {
pub fn new() -> Self {
GCRequester {
request_sync: Mutex::new(RequestSync {
request_count: 0,
last_request_count: -1,
}),
request_condvar: Condvar::new(),
request_flag: AtomicBool::new(false),
phantom: PhantomData,
}
}
pub fn request(&self) {
if self.request_flag.load(Ordering::Relaxed) {
return;
}
let mut guard = self.request_sync.lock().unwrap();
if !self.request_flag.load(Ordering::Relaxed) {
self.request_flag.store(true, Ordering::Relaxed);
guard.request_count += 1;
self.request_condvar.notify_all();
}
}
pub fn clear_request(&self) {
let guard = self.request_sync.lock().unwrap();
self.request_flag.store(false, Ordering::Relaxed);
drop(guard);
}
pub fn wait_for_request(&self) {
let mut guard = self.request_sync.lock().unwrap();
guard.last_request_count += 1;
while guard.last_request_count == guard.request_count {
guard = self.request_condvar.wait(guard).unwrap();
}
}
}