use crate::config::{GC_CANCELLATION as CONFIG_CANCELLATION, GcParked};
#[derive(Default)]
pub struct CancellableGuard {
cancelled: bool,
}
impl CancellableGuard {
pub fn new() -> Self {
Self { cancelled: false }
}
pub fn is_cancelled(&self) -> bool {
self.cancelled
}
pub fn set_cancelled(&mut self) {
self.cancelled = true;
}
}
impl Drop for CancellableGuard {
fn drop(&mut self) {
}
}
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 with_cancellation_check<T, E: std::fmt::Debug>(
f: impl FnOnce() -> Result<T, E>,
) -> Result<T, GcParked> {
check_cancellation()?;
f().map_err(|_| GcParked)
}
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(())
}
}
}