shadow_shim_helper_rs/rootedcell/
refcell.rs

1use std::cell::{Cell, UnsafeCell};
2
3use vasi::VirtualAddressSpaceIndependent;
4
5use crate::explicit_drop::ExplicitDrop;
6
7use super::{Root, Tag};
8
9/// Analagous to [std::cell::RefCell]. In particular like [std::cell::RefCell]
10/// and unlike [std::sync::Mutex], it  doesn't perform any atomic operations
11/// internally, making it relatively inexpensive.
12///
13/// Unlike [std::cell::RefCell], this type is [Send] and [Sync] if `T` is
14/// [Send]. This is safe because the owner is required to prove access to the
15/// associated [Root], which is `![Sync]`, to borrow.
16#[derive(Debug, VirtualAddressSpaceIndependent)]
17#[repr(C)]
18pub struct RootedRefCell<T> {
19    tag: Tag,
20    val: UnsafeCell<T>,
21    reader_count: Cell<u32>,
22    writer: Cell<bool>,
23}
24
25impl<T> RootedRefCell<T> {
26    /// Create a RootedRefCell associated with `root`.
27    #[inline]
28    pub fn new(root: &Root, val: T) -> Self {
29        Self {
30            tag: root.tag(),
31            val: UnsafeCell::new(val),
32            reader_count: Cell::new(0),
33            writer: Cell::new(false),
34        }
35    }
36
37    /// Borrow a reference. Panics if `root` is for the wrong [Root], or
38    /// if this object is alread mutably borrowed.
39    #[inline]
40    pub fn borrow<'a>(&'a self, root: &'a Root) -> RootedRefCellRef<'a, T> {
41        // Prove that the root is held for this tag.
42        assert_eq!(
43            root.tag, self.tag,
44            "Expected {:?} Got {:?}",
45            self.tag, root.tag
46        );
47
48        assert!(!self.writer.get());
49
50        self.reader_count.set(self.reader_count.get() + 1);
51
52        RootedRefCellRef { guard: self }
53    }
54
55    /// Borrow a mutable reference. Panics if `root` is for the wrong
56    /// [Root], or if this object is already borrowed.
57    #[inline]
58    pub fn borrow_mut<'a>(&'a self, root: &'a Root) -> RootedRefCellRefMut<'a, T> {
59        // Prove that the root is held for this tag.
60        assert_eq!(
61            root.tag, self.tag,
62            "Expected {:?} Got {:?}",
63            self.tag, root.tag
64        );
65
66        assert!(!self.writer.get());
67        assert!(self.reader_count.get() == 0);
68
69        self.writer.set(true);
70
71        RootedRefCellRefMut { guard: self }
72    }
73
74    #[inline]
75    pub fn into_inner(self) -> T {
76        self.val.into_inner()
77    }
78}
79
80unsafe impl<T: Send> Send for RootedRefCell<T> {}
81unsafe impl<T: Send> Sync for RootedRefCell<T> {}
82
83impl<T> ExplicitDrop for RootedRefCell<T>
84where
85    T: ExplicitDrop,
86{
87    type ExplicitDropParam = <T as ExplicitDrop>::ExplicitDropParam;
88    type ExplicitDropResult = <T as ExplicitDrop>::ExplicitDropResult;
89
90    fn explicit_drop(self, param: &Self::ExplicitDropParam) -> Self::ExplicitDropResult {
91        self.val.into_inner().explicit_drop(param)
92    }
93}
94
95pub struct RootedRefCellRef<'a, T> {
96    guard: &'a RootedRefCell<T>,
97}
98
99impl<T> std::ops::Deref for RootedRefCellRef<'_, T> {
100    type Target = T;
101
102    #[inline]
103    fn deref(&self) -> &Self::Target {
104        unsafe { self.guard.val.get().as_ref().unwrap() }
105    }
106}
107
108impl<T> Drop for RootedRefCellRef<'_, T> {
109    #[inline]
110    fn drop(&mut self) {
111        self.guard
112            .reader_count
113            .set(self.guard.reader_count.get() - 1);
114    }
115}
116
117pub struct RootedRefCellRefMut<'a, T> {
118    guard: &'a RootedRefCell<T>,
119}
120
121impl<T> std::ops::Deref for RootedRefCellRefMut<'_, T> {
122    type Target = T;
123
124    #[inline]
125    fn deref(&self) -> &Self::Target {
126        unsafe { self.guard.val.get().as_ref().unwrap() }
127    }
128}
129
130impl<T> std::ops::DerefMut for RootedRefCellRefMut<'_, T> {
131    #[inline]
132    fn deref_mut(&mut self) -> &mut Self::Target {
133        unsafe { self.guard.val.get().as_mut().unwrap() }
134    }
135}
136
137impl<T> Drop for RootedRefCellRefMut<'_, T> {
138    #[inline]
139    fn drop(&mut self) {
140        self.guard.writer.set(false);
141    }
142}
143
144#[cfg(test)]
145mod test_rooted_refcell {
146    use std::thread;
147
148    use super::*;
149    use crate::explicit_drop::ExplicitDrop;
150    use crate::rootedcell::rc::RootedRc;
151
152    #[test]
153    fn construct_and_drop() {
154        let root = Root::new();
155        let _ = RootedRefCell::new(&root, 0);
156    }
157
158    #[test]
159    fn share_with_worker_thread() {
160        let root = Root::new();
161        let rc = RootedRc::new(&root, RootedRefCell::new(&root, 0));
162        let root = {
163            let rc = { rc.clone(&root) };
164            thread::spawn(move || {
165                let mut borrow = rc.borrow_mut(&root);
166                *borrow = 3;
167                // Drop rc with lock still held.
168                drop(borrow);
169                rc.explicit_drop(&root);
170                root
171            })
172            .join()
173            .unwrap()
174        };
175        let borrow = rc.borrow(&root);
176        assert_eq!(*borrow, 3);
177        drop(borrow);
178        rc.explicit_drop(&root);
179    }
180}