Skip to main content

dark_std/sync/
mod.rs

1pub mod map_btree;
2pub mod map_hash;
3pub mod map_index;
4pub mod vec;
5pub mod wg;
6
7pub mod duration;
8
9use parking_lot::{Mutex, MutexGuard};
10use std::boxed::Box;
11use std::cell::{Cell, RefCell};
12use std::fmt::{Debug, Display, Formatter};
13use std::marker::PhantomData;
14use std::ops::{Deref, DerefMut};
15use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
16
17/// Per-thread reader slots.
18///
19/// Every thread that reads a container remembers the location of its private
20/// reader counter in that container's registry (a `Box<AtomicUsize>` that is
21/// owned by the container and never moves). The counter is only written by its
22/// owning thread, so concurrent readers touch their own cache line and never
23/// contend with each other; writers scan the registry to know when all readers
24/// are gone. Entries for dropped containers are simply never used again (each
25/// container has a unique `id`, so address reuse cannot alias a stale entry).
26struct ReaderSlots {
27    // Fast path: most threads read only one container, so cache the last
28    // (container id -> counter) pair to avoid scanning the vector every read.
29    last: Cell<(usize, *const AtomicUsize)>,
30    all: RefCell<Vec<(usize, *const AtomicUsize)>>,
31}
32
33thread_local! {
34    static SLOTS: ReaderSlots = ReaderSlots {
35        last: Cell::new((usize::MAX, std::ptr::null())),
36        all: RefCell::new(Vec::new()),
37    };
38}
39
40/// Returns (and lazily registers) the current thread's reader counter for the
41/// container identified by `id`, adding it to `registry` on first use. The
42/// returned reference is valid for as long as the registry (i.e. the
43/// container) lives.
44pub(crate) fn reader_count_for<'a>(
45    id: usize,
46    registry: &'a Mutex<Vec<Box<AtomicUsize>>>,
47) -> &'a AtomicUsize {
48    SLOTS.with(|slots| {
49        let (last_id, last_ptr) = slots.last.get();
50        if last_id == id && !last_ptr.is_null() {
51            // SAFETY: the counter lives in `registry`, which is borrowed for
52            // 'a and never removes entries, so the Box address stays valid.
53            return unsafe { &*last_ptr };
54        }
55        let mut all = slots.all.borrow_mut();
56        if let Some((_, c)) = all.iter().find(|(k, _)| *k == id) {
57            slots.last.set((id, *c));
58            // SAFETY: the counter lives in `registry`, borrowed for 'a, and
59            // registry entries are never removed, so the address stays valid.
60            return unsafe { &**c };
61        }
62        let mut reg = registry.lock();
63        reg.push(Box::new(AtomicUsize::new(0)));
64        let ptr: *const AtomicUsize = &**reg.last().unwrap();
65        all.push((id, ptr));
66        slots.last.set((id, ptr));
67        // SAFETY: the newly pushed Box is in `registry` (borrowed for 'a) and
68        // never moves, so this reference stays valid for 'a.
69        unsafe { &*ptr }
70    })
71}
72
73/// Unique id source for containers, so a thread-local slot can never alias a
74/// different container that happens to reuse the same memory address.
75pub(crate) static CONTAINER_ID: AtomicUsize = AtomicUsize::new(0);
76
77/// An RAII read guard returned by the `get` methods of the synchronous
78/// containers (`SyncHashMap`, `SyncBtreeMap`, `SyncVec`, `SyncIndexMap`).
79///
80/// Reading the value is lock-free and contention-free: the guard only holds a
81/// reader slot in the calling thread's private counter (writers wait for all
82/// threads' counters to drain before mutating), so the pointed-to value can
83/// never be invalidated or raced while the guard is alive. It is not `Send`:
84/// it must be dropped on the same thread that created it.
85pub struct ReadGuard<'a, V> {
86    count: &'a AtomicUsize,
87    value: &'a V,
88    _not_send: PhantomData<*const ()>,
89}
90
91impl<'a, V> ReadGuard<'a, V> {
92    #[inline]
93    pub(crate) fn new(count: &'a AtomicUsize, value: &'a V) -> Self {
94        ReadGuard {
95            count,
96            value,
97            _not_send: PhantomData,
98        }
99    }
100}
101
102impl<'a, V> Deref for ReadGuard<'a, V> {
103    type Target = V;
104
105    #[inline]
106    fn deref(&self) -> &Self::Target {
107        self.value
108    }
109}
110
111impl<'a, V> Drop for ReadGuard<'a, V> {
112    fn drop(&mut self) {
113        self.count.fetch_sub(1, Ordering::Release);
114    }
115}
116
117impl<'a, V: Debug> Debug for ReadGuard<'a, V> {
118    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
119        Debug::fmt(self.value, f)
120    }
121}
122
123impl<'a, V: Display> Display for ReadGuard<'a, V> {
124    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125        Display::fmt(self.value, f)
126    }
127}
128
129impl<'a, V: PartialEq> PartialEq for ReadGuard<'a, V> {
130    fn eq(&self, other: &Self) -> bool {
131        **self == **other
132    }
133}
134
135impl<'a, V: Eq> Eq for ReadGuard<'a, V> {}
136
137impl<'a, V: PartialEq> PartialEq<V> for ReadGuard<'a, V> {
138    fn eq(&self, other: &V) -> bool {
139        **self == *other
140    }
141}
142
143impl<'a, V: PartialEq> PartialEq<&V> for ReadGuard<'a, V> {
144    fn eq(&self, other: &&V) -> bool {
145        **self == **other
146    }
147}
148
149/// A read guard for whole-container access (`iter`, `dirty_ref`, ...).
150///
151/// Reading is lock-free and contention-free; the guard only pins a reader slot
152/// in the calling thread's private counter. It is not `Send`: it must be
153/// dropped on the same thread that created it.
154pub struct ReadMapGuard<'a, C> {
155    count: &'a AtomicUsize,
156    value: &'a C,
157    _not_send: PhantomData<*const ()>,
158}
159
160impl<'a, C> ReadMapGuard<'a, C> {
161    #[inline]
162    pub(crate) fn new(count: &'a AtomicUsize, value: &'a C) -> Self {
163        ReadMapGuard {
164            count,
165            value,
166            _not_send: PhantomData,
167        }
168    }
169}
170
171impl<'a, C> Deref for ReadMapGuard<'a, C> {
172    type Target = C;
173
174    #[inline]
175    fn deref(&self) -> &Self::Target {
176        self.value
177    }
178}
179
180impl<'a, C> Drop for ReadMapGuard<'a, C> {
181    fn drop(&mut self) {
182        self.count.fetch_sub(1, Ordering::Release);
183    }
184}
185
186impl<'a, C: Debug> Debug for ReadMapGuard<'a, C> {
187    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
188        Debug::fmt(self.value, f)
189    }
190}
191
192impl<'a, C: Display> Display for ReadMapGuard<'a, C> {
193    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
194        Display::fmt(self.value, f)
195    }
196}
197
198/// Internal RAII token for the write path: holds the writer mutex and keeps
199/// the `writing` flag set until dropped, so readers know a writer is active.
200pub(crate) struct WriteLock<'a> {
201    _lock: MutexGuard<'a, ()>,
202    writing: &'a AtomicBool,
203}
204
205impl<'a> WriteLock<'a> {
206    #[inline]
207    pub(crate) fn new(_lock: MutexGuard<'a, ()>, writing: &'a AtomicBool) -> Self {
208        WriteLock { _lock, writing }
209    }
210}
211
212impl<'a> Drop for WriteLock<'a> {
213    fn drop(&mut self) {
214        self.writing.store(false, Ordering::SeqCst);
215    }
216}
217
218/// An RAII write guard returned by the `get_mut` methods of the synchronous
219/// containers (`SyncHashMap`, `SyncBtreeMap`, `SyncVec`, `SyncIndexMap`).
220///
221/// It holds the writer lock (and the `writing` flag) until dropped, so no
222/// reader or writer can touch the value while the guard is alive.
223pub struct WriteGuard<'a, V> {
224    _w: WriteLock<'a>,
225    value: &'a mut V,
226}
227
228impl<'a, V> WriteGuard<'a, V> {
229    #[inline]
230    pub(crate) fn new(_w: WriteLock<'a>, value: &'a mut V) -> Self {
231        WriteGuard { _w, value }
232    }
233}
234
235impl<'a, V> Deref for WriteGuard<'a, V> {
236    type Target = V;
237
238    #[inline]
239    fn deref(&self) -> &Self::Target {
240        &*self.value
241    }
242}
243
244impl<'a, V> DerefMut for WriteGuard<'a, V> {
245    #[inline]
246    fn deref_mut(&mut self) -> &mut Self::Target {
247        &mut *self.value
248    }
249}
250
251impl<'a, V: Debug> Debug for WriteGuard<'a, V> {
252    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
253        Debug::fmt(&*self.value, f)
254    }
255}
256
257impl<'a, V: Display> Display for WriteGuard<'a, V> {
258    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
259        Display::fmt(&*self.value, f)
260    }
261}
262
263impl<'a, V: PartialEq> PartialEq for WriteGuard<'a, V> {
264    fn eq(&self, other: &Self) -> bool {
265        **self == **other
266    }
267}
268
269impl<'a, V: Eq> Eq for WriteGuard<'a, V> {}
270
271pub use duration::*;
272pub use map_btree::SyncBtreeMap;
273pub use map_hash::SyncHashMap;
274pub use map_index::SyncIndexMap;
275pub use vec::*;
276pub use wg::*;