use crate::config::{GC_CANCELLATION as CONFIG_CANCELLATION, GcParked};
pub fn check_cancellation() -> Result<(), GcParked> {
CONFIG_CANCELLATION.check()
}
pub fn safepoint() {
if !CONFIG_CANCELLATION.in_progress() {
return;
}
CONFIG_CANCELLATION.park();
while CONFIG_CANCELLATION.in_progress() {
std::thread::yield_now();
}
CONFIG_CANCELLATION.unpark();
}
pub fn register_mutator() -> MutatorGuard {
CONFIG_CANCELLATION.register_thread();
MutatorGuard { _private: () }
}
pub struct MutatorGuard {
_private: (),
}
impl Drop for MutatorGuard {
fn drop(&mut self) {
CONFIG_CANCELLATION.unregister_thread();
}
}
pub fn request_gc() {
CONFIG_CANCELLATION.request_gc();
}
pub fn gc_requested() -> bool {
CONFIG_CANCELLATION.gc_requested()
}
pub fn take_gc_request() -> bool {
CONFIG_CANCELLATION.take_gc_request()
}
pub fn wait_for_threads_to_park() -> usize {
let expected = CONFIG_CANCELLATION.registered_threads().saturating_sub(1);
if expected == 0 {
return 0;
}
loop {
let parked = CONFIG_CANCELLATION.parked_threads();
if parked >= expected {
return parked;
}
std::thread::yield_now();
}
}
pub fn begin_stw() -> Option<StwGuard> {
if !CONFIG_CANCELLATION.try_begin_collection() {
return None;
}
wait_for_threads_to_park();
Some(StwGuard { _private: () })
}
pub struct StwGuard {
_private: (),
}
impl Drop for StwGuard {
fn drop(&mut self) {
CONFIG_CANCELLATION.set_in_progress(false);
}
}
pub fn park_thread() {
CONFIG_CANCELLATION.park();
}
pub fn unpark_thread() {
CONFIG_CANCELLATION.unpark();
}
pub fn parked_threads() -> usize {
CONFIG_CANCELLATION.parked_threads()
}
pub fn registered_threads() -> usize {
CONFIG_CANCELLATION.registered_threads()
}
pub trait GcCancellationExt {
fn check(&self) -> Result<(), GcParked>;
}
impl GcCancellationExt for crate::config::GcCancellation {
fn check(&self) -> Result<(), GcParked> {
if self.in_progress() {
Err(GcParked)
} else {
Ok(())
}
}
}