1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
use crate::scheduler::GCWorkScheduler;
use crate::vm::VMBinding;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
/// This data structure lets mutators trigger GC.
pub struct GCRequester<VM: VMBinding> {
/// Set by mutators to trigger GC. It is atomic so that mutators can check if GC has already
/// been requested efficiently in `poll` without acquiring any mutex.
request_flag: AtomicBool,
scheduler: Arc<GCWorkScheduler<VM>>,
}
impl<VM: VMBinding> GCRequester<VM> {
pub fn new(scheduler: Arc<GCWorkScheduler<VM>>) -> Self {
GCRequester {
request_flag: AtomicBool::new(false),
scheduler,
}
}
/// Request a GC. Called by mutators when polling (during allocation) and when handling user
/// GC requests (e.g. `System.gc();` in Java).
pub fn request(&self) {
if self.request_flag.load(Ordering::Relaxed) {
return;
}
if !self.request_flag.swap(true, Ordering::Relaxed) {
// `GCWorkScheduler::request_schedule_collection` needs to hold a mutex to communicate
// with GC workers, which is expensive for functions like `poll`. We use the atomic
// flag `request_flag` to elide the need to acquire the mutex in subsequent calls.
self.scheduler.request_schedule_collection();
}
}
/// Clear the "GC requested" flag so that mutators can trigger the next GC.
/// Called by a GC worker when all mutators have come to a stop.
pub fn clear_request(&self) {
self.request_flag.store(false, Ordering::Relaxed);
}
}