gix_tempfile/registry.rs
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
use crate::REGISTRY;
/// Remove all tempfiles still registered on our global registry, and leak their data to be signal-safe.
/// This happens on a best-effort basis with all errors being ignored.
///
/// # Safety
/// Note that Mutexes of any kind are not allowed, and so aren't allocation or deallocation of memory.
/// We are using lock-free datastructures and sprinkle in `std::mem::forget` to avoid deallocating.
/// Most importantly, we use `try_lock()` which uses an atomic int only without blocking, making our register method safe to use,
/// at the expense of possibly missing a lock file if another thread wants to obtain it or put it back
/// (i.e. mutates the registry shard).
pub fn cleanup_tempfiles_signal_safe() {
let current_pid = std::process::id();
#[cfg(feature = "hp-hashmap")]
{
use std::sync::atomic::Ordering;
use crate::NEXT_MAP_INDEX;
let one_past_last_index = NEXT_MAP_INDEX.load(Ordering::SeqCst);
for idx in 0..one_past_last_index {
if let Some(entry) = REGISTRY.try_entry(idx) {
entry.and_modify(|tempfile| {
if tempfile
.as_ref()
.map_or(false, |tf| tf.owning_process_id == current_pid)
{
if let Some(tempfile) = tempfile.take() {
tempfile.drop_without_deallocation();
}
}
});
}
}
}
#[cfg(not(feature = "hp-hashmap"))]
{
REGISTRY.for_each(|tf| {
if tf.as_ref().map_or(false, |tf| tf.owning_process_id == current_pid) {
if let Some(tf) = tf.take() {
tf.drop_without_deallocation();
}
}
});
}
}
/// Remove all tempfiles still registered on our global registry.
/// This happens on a best-effort basis with all errors being ignored.
///
/// # Note
///
/// Must not be called from within signal hooks. For that, use [`cleanup_tempfiles_signal_safe()`].
pub fn cleanup_tempfiles() {
let current_pid = std::process::id();
#[cfg(feature = "hp-hashmap")]
REGISTRY.iter_mut().for_each(|mut tf| {
if tf.as_ref().map_or(false, |tf| tf.owning_process_id == current_pid) {
tf.take();
}
});
#[cfg(not(feature = "hp-hashmap"))]
REGISTRY.for_each(|tf| {
if tf.as_ref().map_or(false, |tf| tf.owning_process_id == current_pid) {
tf.take();
}
});
}