-
Notifications
You must be signed in to change notification settings - Fork 63
/
finalizers.rs
57 lines (49 loc) · 1.93 KB
/
finalizers.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
use gc_arena::{lock::RefLock, Collect, Finalization, Gc, GcWeak, Mutation};
use crate::{thread::ThreadInner, Thread};
#[derive(Copy, Clone, Collect)]
#[collect(no_drop)]
pub struct Finalizers<'gc>(Gc<'gc, RefLock<FinalizersState<'gc>>>);
impl<'gc> Finalizers<'gc> {
const THREAD_ERR: &'static str = "thread finalization was missed";
pub(crate) fn new(mc: &Mutation<'gc>) -> Self {
Finalizers(Gc::new(mc, RefLock::default()))
}
pub(crate) fn register_thread(&self, mc: &Mutation<'gc>, ptr: Gc<'gc, ThreadInner<'gc>>) {
self.0.borrow_mut(mc).threads.push(Gc::downgrade(ptr));
}
/// First stage of two-stage finalization.
///
/// This stage can cause resurrection, so the arena must be *fully re-marked* before stage two
/// (`Finalizers::finalize`).
pub(crate) fn prepare(&self, fc: &Finalization<'gc>) {
let state = self.0.borrow();
for &ptr in &state.threads {
let thread = Thread::from_inner(ptr.upgrade(fc).expect(Self::THREAD_ERR));
thread.resurrect_live_upvalues(fc).unwrap();
}
}
/// Second stage of two-stage finalization.
///
/// Assuming stage one was called (`Finalizers::prepare`) and the arena fully re-marked, this
/// method will *not* cause any resurrection.
///
/// The arena must *immediately* transition to `CollectionPhase::Collecting` afterwards to not
/// miss any finalizers.
pub(crate) fn finalize(&self, fc: &Finalization<'gc>) {
let mut state = self.0.borrow_mut(fc);
state.threads.retain(|&ptr| {
let ptr = ptr.upgrade(fc).expect(Self::THREAD_ERR);
if Gc::is_dead(fc, ptr) {
Thread::from_inner(ptr).reset(fc).unwrap();
false
} else {
true
}
});
}
}
#[derive(Default, Collect)]
#[collect(no_drop)]
struct FinalizersState<'gc> {
threads: Vec<GcWeak<'gc, ThreadInner<'gc>>>,
}