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

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

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

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

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

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

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

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

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

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

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

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