1
use std::cell::UnsafeCell;
2
use std::mem::ManuallyDrop;
3
use std::ops::Deref;
4
use std::ops::DerefMut;
5

            
6
use crate::storage::GlobalTermPoolGuard;
7
use crate::storage::THREAD_TERM_POOL;
8

            
9
/// Global mutex that prevents garbage collection.
10
pub struct GcMutex<T> {
11
    inner: UnsafeCell<T>,
12
}
13

            
14
unsafe impl<T: Send> Send for GcMutex<T> {}
15
unsafe impl<T: Send> Sync for GcMutex<T> {}
16

            
17
impl<T> GcMutex<T> {
18
3335748
    pub fn new(value: T) -> GcMutex<T> {
19
3335748
        GcMutex {
20
3335748
            inner: UnsafeCell::new(value),
21
3335748
        }
22
3335748
    }
23

            
24
    /// Provides mutable access to the underlying value.
25
39880349
    pub fn write(&self) -> GcMutexGuard<'_, T> {
26
        GcMutexGuard {
27
39880349
            mutex: self,
28
39880349
            guard: ManuallyDrop::new(THREAD_TERM_POOL.with_borrow(|tp| unsafe {
29
39880349
                std::mem::transmute(tp.term_pool().read_recursive().expect("Lock poisoned!"))
30
39880349
            })),
31
        }
32
39880349
    }
33

            
34
    /// Provides immutable access to the underlying value.
35
25705650
    pub fn read(&self) -> GcMutexGuard<'_, T> {
36
        GcMutexGuard {
37
25705650
            mutex: self,
38
25705650
            guard: ManuallyDrop::new(THREAD_TERM_POOL.with_borrow(|tp| unsafe {
39
25705650
                std::mem::transmute(tp.term_pool().read_recursive().expect("Lock poisoned!"))
40
25705650
            })),
41
        }
42
25705650
    }
43
}
44

            
45
pub struct GcMutexGuard<'a, T> {
46
    mutex: &'a GcMutex<T>,
47

            
48
    /// Only used to avoid garbage collection, will be released on drop.
49
    guard: ManuallyDrop<GlobalTermPoolGuard<'a>>,
50
}
51

            
52
impl<T> Deref for GcMutexGuard<'_, T> {
53
    type Target = T;
54

            
55
288253621
    fn deref(&self) -> &Self::Target {
56
288253621
        unsafe { &*self.mutex.inner.get() }
57
288253621
    }
58
}
59

            
60
impl<T> DerefMut for GcMutexGuard<'_, T> {
61
60552052
    fn deref_mut(&mut self) -> &mut Self::Target {
62
        // We are the only guard after `write()`, so we can provide mutable access to the underlying object.
63
60552052
        unsafe { &mut *self.mutex.inner.get() }
64
60552052
    }
65
}
66

            
67
impl<T> Drop for GcMutexGuard<'_, T> {
68
65585999
    fn drop(&mut self) {
69
65585999
        if self.guard.read_depth() == 1 {
70
            // If this is the last guard, we can trigger garbage collection when it was delayed earlier.
71
26043446
            THREAD_TERM_POOL.with_borrow(|tp| {
72
26043446
                unsafe { tp.trigger_delayed_garbage_collection(&mut self.guard) }
73
26043446
            })
74
39542553
        } else {
75
39542553
            // Just drop the guard
76
39542553
            unsafe { ManuallyDrop::drop(&mut self.guard) };
77
39542553
        }
78
65585999
    }
79
}