/rust/registry/src/index.crates.io-1949cf8c6b5b557f/seize-0.5.1/src/guard.rs
Line | Count | Source |
1 | | use std::fmt; |
2 | | use std::marker::PhantomData; |
3 | | use std::sync::atomic::{AtomicPtr, Ordering}; |
4 | | |
5 | | use crate::raw::{self, Reservation, Thread}; |
6 | | use crate::Collector; |
7 | | |
8 | | /// A guard that enables protected loads of concurrent objects. |
9 | | /// |
10 | | /// This trait provides common functionality implemented by [`LocalGuard`] and |
11 | | /// [`OwnedGuard`]. See [the guide](crate::guide#starting-operations) for an |
12 | | /// introduction to using guards. |
13 | | pub trait Guard { |
14 | | /// Refreshes the guard. |
15 | | /// |
16 | | /// Calling this method is similar to dropping and immediately creating a |
17 | | /// new guard. The current thread remains active, but any pointers that |
18 | | /// were previously protected may be reclaimed. |
19 | | /// |
20 | | /// # Safety |
21 | | /// |
22 | | /// This method is not marked as `unsafe`, but will affect the validity of |
23 | | /// pointers loaded using [`Guard::protect`], similar to dropping a guard. |
24 | | /// It is intended to be used safely by users of concurrent data structures, |
25 | | /// as references will be tied to the guard and this method takes `&mut |
26 | | /// self`. |
27 | | fn refresh(&mut self); |
28 | | |
29 | | /// Flush any retired values in the local batch. |
30 | | /// |
31 | | /// This method flushes any values from the current thread's local batch, |
32 | | /// starting the reclamation process. Note that no memory can be |
33 | | /// reclaimed while this guard is active, but calling `flush` may allow |
34 | | /// memory to be reclaimed more quickly after the guard is dropped. |
35 | | /// |
36 | | /// Note that the batch must contain at least as many objects as the number |
37 | | /// of currently active threads for a flush to be performed. See |
38 | | /// [`Collector::batch_size`] for details about batch sizes. |
39 | | fn flush(&self); |
40 | | |
41 | | /// Returns the collector this guard was created from. |
42 | | fn collector(&self) -> &Collector; |
43 | | |
44 | | /// Returns a numeric identifier for the current thread. |
45 | | /// |
46 | | /// Guards rely on thread-local state, including thread IDs. This method is |
47 | | /// a cheap way to get an identifier for the current thread without TLS |
48 | | /// overhead. Note that thread IDs may be reused, so the value returned |
49 | | /// is only unique for the lifetime of this thread. |
50 | | fn thread_id(&self) -> usize; |
51 | | |
52 | | /// Protects the load of an atomic pointer. |
53 | | /// |
54 | | /// Any valid pointer loaded through a guard using the `protect` method is |
55 | | /// guaranteed to stay valid until the guard is dropped, or the object |
56 | | /// is retired by the current thread. Importantly, if another thread |
57 | | /// retires this object, it will not be reclaimed for the lifetime of |
58 | | /// this guard. |
59 | | /// |
60 | | /// Note that the lifetime of a guarded pointer is logically tied to that of |
61 | | /// the guard — when the guard is dropped the pointer is invalidated. Data |
62 | | /// structures that return shared references to values should ensure that |
63 | | /// the lifetime of the reference is tied to the lifetime of a guard. |
64 | 171k | fn protect<T>(&self, ptr: &AtomicPtr<T>, order: Ordering) -> *mut T { |
65 | 171k | ptr.load(raw::Collector::protect(order)) |
66 | 171k | } Unexecuted instantiation: <papaya::raw::utils::MapGuard<seize::guard::LocalGuard> as seize::guard::Guard>::protect::<papaya::raw::Entry<bytes::bytes::Bytes, ()>> <papaya::raw::utils::MapGuard<seize::guard::LocalGuard> as seize::guard::Guard>::protect::<papaya::raw::alloc::RawTable<papaya::raw::Entry<bytes::bytes::Bytes, ()>>> Line | Count | Source | 64 | 171k | fn protect<T>(&self, ptr: &AtomicPtr<T>, order: Ordering) -> *mut T { | 65 | 171k | ptr.load(raw::Collector::protect(order)) | 66 | 171k | } |
Unexecuted instantiation: <_ as seize::guard::Guard>::protect::<_> |
67 | | |
68 | | /// Stores a value into the pointer, returning the protected previous value. |
69 | | /// |
70 | | /// This method is equivalent to [`AtomicPtr::swap`], except the returned |
71 | | /// value is guaranteed to be protected with the same guarantees as |
72 | | /// [`Guard::protect`]. |
73 | 0 | fn swap<T>(&self, ptr: &AtomicPtr<T>, value: *mut T, order: Ordering) -> *mut T { |
74 | 0 | ptr.swap(value, raw::Collector::protect(order)) |
75 | 0 | } |
76 | | |
77 | | /// Stores a value into the pointer if the current value is the same as the |
78 | | /// `current` value, returning the protected previous value. |
79 | | /// |
80 | | /// This method is equivalent to [`AtomicPtr::compare_exchange`], except the |
81 | | /// returned value is guaranteed to be protected with the same |
82 | | /// guarantees as [`Guard::protect`]. |
83 | 0 | fn compare_exchange<T>( |
84 | 0 | &self, |
85 | 0 | ptr: &AtomicPtr<T>, |
86 | 0 | current: *mut T, |
87 | 0 | new: *mut T, |
88 | 0 | success: Ordering, |
89 | 0 | failure: Ordering, |
90 | 0 | ) -> Result<*mut T, *mut T> { |
91 | 0 | ptr.compare_exchange( |
92 | 0 | current, |
93 | 0 | new, |
94 | 0 | raw::Collector::protect(success), |
95 | 0 | raw::Collector::protect(failure), |
96 | | ) |
97 | 0 | } Unexecuted instantiation: <papaya::raw::utils::MapGuard<seize::guard::LocalGuard> as seize::guard::Guard>::compare_exchange::<papaya::raw::Entry<bytes::bytes::Bytes, ()>> Unexecuted instantiation: <_ as seize::guard::Guard>::compare_exchange::<_> |
98 | | |
99 | | /// Stores a value into the pointer if the current value is the same as the |
100 | | /// `current` value, returning the protected previous value. |
101 | | /// |
102 | | /// This method is equivalent to [`AtomicPtr::compare_exchange_weak`], |
103 | | /// except the returned value is guaranteed to be protected with the |
104 | | /// same guarantees as [`Guard::protect`]. |
105 | 0 | fn compare_exchange_weak<T>( |
106 | 0 | &self, |
107 | 0 | ptr: &AtomicPtr<T>, |
108 | 0 | current: *mut T, |
109 | 0 | new: *mut T, |
110 | 0 | success: Ordering, |
111 | 0 | failure: Ordering, |
112 | 0 | ) -> Result<*mut T, *mut T> { |
113 | 0 | ptr.compare_exchange_weak( |
114 | 0 | current, |
115 | 0 | new, |
116 | 0 | raw::Collector::protect(success), |
117 | 0 | raw::Collector::protect(failure), |
118 | | ) |
119 | 0 | } Unexecuted instantiation: <papaya::raw::utils::MapGuard<seize::guard::LocalGuard> as seize::guard::Guard>::compare_exchange_weak::<papaya::raw::Entry<bytes::bytes::Bytes, ()>> Unexecuted instantiation: <_ as seize::guard::Guard>::compare_exchange_weak::<_> |
120 | | |
121 | | /// Retires a value, running `reclaim` when no threads hold a reference to |
122 | | /// it. |
123 | | /// |
124 | | /// This method delays reclamation until the guard is dropped, as opposed to |
125 | | /// [`Collector::retire`], which may reclaim objects immediately. |
126 | | /// |
127 | | /// |
128 | | /// # Safety |
129 | | /// |
130 | | /// The retired pointer must no longer be accessible to any thread that |
131 | | /// enters after it is removed. Additionally, the pointer must be valid |
132 | | /// to pass to the provided reclaimer, once it is safe to reclaim. |
133 | | unsafe fn defer_retire<T>(&self, ptr: *mut T, reclaim: unsafe fn(*mut T, &Collector)); |
134 | | } |
135 | | |
136 | | /// A guard that keeps the current thread marked as active. |
137 | | /// |
138 | | /// Local guards are created by calling [`Collector::enter`]. Unlike |
139 | | /// [`OwnedGuard`], a local guard is tied to the current thread and does not |
140 | | /// implement `Send`. This makes local guards relatively cheap to create and |
141 | | /// destroy. |
142 | | /// |
143 | | /// Most of the functionality provided by this type is through the [`Guard`] |
144 | | /// trait. |
145 | | pub struct LocalGuard<'a> { |
146 | | /// The collector that this guard is associated with. |
147 | | collector: &'a Collector, |
148 | | |
149 | | // The current thread. |
150 | | thread: Thread, |
151 | | |
152 | | // The reservation for the current thread. |
153 | | reservation: *const Reservation, |
154 | | |
155 | | // `LocalGuard` not be `Send or Sync` as we are tied to the state of the |
156 | | // current thread in the collector. |
157 | | _unsend: PhantomData<*mut ()>, |
158 | | } |
159 | | |
160 | | impl LocalGuard<'_> { |
161 | | #[inline] |
162 | 171k | pub(crate) fn enter(collector: &Collector) -> LocalGuard<'_> { |
163 | 171k | let thread = Thread::current(); |
164 | | |
165 | | // Safety: `thread` is the current thread. |
166 | 171k | let reservation = unsafe { collector.raw.reservation(thread) }; |
167 | | |
168 | | // Calls to `enter` may be reentrant, so we need to keep track of the number of |
169 | | // active guards for the current thread. |
170 | 171k | let guards = reservation.guards.get(); |
171 | 171k | reservation.guards.set(guards + 1); |
172 | | |
173 | 171k | if guards == 0 { |
174 | 171k | // Safety: Only called on the current thread, which is currently inactive. |
175 | 171k | unsafe { collector.raw.enter(reservation) }; |
176 | 171k | } |
177 | | |
178 | 171k | LocalGuard { |
179 | 171k | thread, |
180 | 171k | reservation, |
181 | 171k | collector, |
182 | 171k | _unsend: PhantomData, |
183 | 171k | } |
184 | 171k | } <seize::guard::LocalGuard>::enter Line | Count | Source | 162 | 171k | pub(crate) fn enter(collector: &Collector) -> LocalGuard<'_> { | 163 | 171k | let thread = Thread::current(); | 164 | | | 165 | | // Safety: `thread` is the current thread. | 166 | 171k | let reservation = unsafe { collector.raw.reservation(thread) }; | 167 | | | 168 | | // Calls to `enter` may be reentrant, so we need to keep track of the number of | 169 | | // active guards for the current thread. | 170 | 171k | let guards = reservation.guards.get(); | 171 | 171k | reservation.guards.set(guards + 1); | 172 | | | 173 | 171k | if guards == 0 { | 174 | 171k | // Safety: Only called on the current thread, which is currently inactive. | 175 | 171k | unsafe { collector.raw.enter(reservation) }; | 176 | 171k | } | 177 | | | 178 | 171k | LocalGuard { | 179 | 171k | thread, | 180 | 171k | reservation, | 181 | 171k | collector, | 182 | 171k | _unsend: PhantomData, | 183 | 171k | } | 184 | 171k | } |
Unexecuted instantiation: <seize::guard::LocalGuard>::enter |
185 | | } |
186 | | |
187 | | impl Guard for LocalGuard<'_> { |
188 | | /// Refreshes the guard. |
189 | | #[inline] |
190 | 0 | fn refresh(&mut self) { |
191 | | // Safety: `self.reservation` is owned by the current thread. |
192 | 0 | let reservation = unsafe { &*self.reservation }; |
193 | 0 | let guards = reservation.guards.get(); |
194 | | |
195 | 0 | if guards == 1 { |
196 | | // Safety: We have a unique reference to the last active guard. |
197 | 0 | unsafe { self.collector.raw.refresh(reservation) } |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | /// Flush any retired values in the local batch. |
202 | | #[inline] |
203 | 0 | fn flush(&self) { |
204 | | // Note that this does not actually retire any values, it just attempts to add |
205 | | // the batch to any active reservations lists, including ours. |
206 | | // |
207 | | // Safety: `self.thread` is the current thread. |
208 | 0 | unsafe { self.collector.raw.try_retire_batch(self.thread) } |
209 | 0 | } |
210 | | |
211 | | /// Returns the collector this guard was created from. |
212 | | #[inline] |
213 | 0 | fn collector(&self) -> &Collector { |
214 | 0 | self.collector |
215 | 0 | } |
216 | | |
217 | | /// Returns a numeric identifier for the current thread. |
218 | | #[inline] |
219 | 0 | fn thread_id(&self) -> usize { |
220 | 0 | self.thread.id |
221 | 0 | } Unexecuted instantiation: <seize::guard::LocalGuard as seize::guard::Guard>::thread_id Unexecuted instantiation: <seize::guard::LocalGuard as seize::guard::Guard>::thread_id |
222 | | |
223 | | /// Retires a value, running `reclaim` when no threads hold a reference to |
224 | | /// it. |
225 | | #[inline] |
226 | 0 | unsafe fn defer_retire<T>(&self, ptr: *mut T, reclaim: unsafe fn(*mut T, &Collector)) { |
227 | | // Safety: |
228 | | // - `self.thread` is the current thread. |
229 | | // - The validity of the pointer is guaranteed by the caller. |
230 | 0 | unsafe { self.collector.raw.add(ptr, reclaim, self.thread) } |
231 | 0 | } Unexecuted instantiation: <seize::guard::LocalGuard as seize::guard::Guard>::defer_retire::<papaya::raw::Entry<bytes::bytes::Bytes, ()>> Unexecuted instantiation: <seize::guard::LocalGuard as seize::guard::Guard>::defer_retire::<papaya::raw::alloc::RawTable<papaya::raw::Entry<bytes::bytes::Bytes, ()>>> Unexecuted instantiation: <seize::guard::LocalGuard as seize::guard::Guard>::defer_retire::<_> |
232 | | } |
233 | | |
234 | | impl Drop for LocalGuard<'_> { |
235 | | #[inline] |
236 | 171k | fn drop(&mut self) { |
237 | | // Safety: `self.reservation` is owned by the current thread. |
238 | 171k | let reservation = unsafe { &*self.reservation }; |
239 | | |
240 | | // Decrement the active guard count. |
241 | 171k | let guards = reservation.guards.get(); |
242 | 171k | reservation.guards.set(guards - 1); |
243 | | |
244 | 171k | if guards == 1 { |
245 | 171k | // Safety: We have a unique reference to the last active guard. |
246 | 171k | unsafe { self.collector.raw.leave(reservation) }; |
247 | 171k | } |
248 | 171k | } <seize::guard::LocalGuard as core::ops::drop::Drop>::drop Line | Count | Source | 236 | 171k | fn drop(&mut self) { | 237 | | // Safety: `self.reservation` is owned by the current thread. | 238 | 171k | let reservation = unsafe { &*self.reservation }; | 239 | | | 240 | | // Decrement the active guard count. | 241 | 171k | let guards = reservation.guards.get(); | 242 | 171k | reservation.guards.set(guards - 1); | 243 | | | 244 | 171k | if guards == 1 { | 245 | 171k | // Safety: We have a unique reference to the last active guard. | 246 | 171k | unsafe { self.collector.raw.leave(reservation) }; | 247 | 171k | } | 248 | 171k | } |
Unexecuted instantiation: <seize::guard::LocalGuard as core::ops::drop::Drop>::drop |
249 | | } |
250 | | |
251 | | impl fmt::Debug for LocalGuard<'_> { |
252 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
253 | 0 | f.debug_tuple("LocalGuard").finish() |
254 | 0 | } |
255 | | } |
256 | | |
257 | | /// A guard that protects objects for it's lifetime, independent of the current |
258 | | /// thread. |
259 | | /// |
260 | | /// Unlike [`LocalGuard`], an owned guard is independent of the current thread, |
261 | | /// allowing it to implement `Send` and `Sync`. This is useful for holding |
262 | | /// guards across `.await` points in work-stealing schedulers, where execution |
263 | | /// may be resumed on a different thread than started on. However, owned guards |
264 | | /// are more expensive to create and destroy, so should be avoided if |
265 | | /// cross-thread usage is not required. |
266 | | /// |
267 | | /// Most of the functionality provided by this type is through the [`Guard`] |
268 | | /// trait. |
269 | | pub struct OwnedGuard<'a> { |
270 | | /// The collector that this guard is associated with. |
271 | | collector: &'a Collector, |
272 | | |
273 | | // An owned thread, unique to this guard. |
274 | | thread: Thread, |
275 | | |
276 | | // The reservation for this guard. |
277 | | reservation: *const Reservation, |
278 | | } |
279 | | |
280 | | // Safety: All shared methods on `OwnedGuard` that access shared memory are |
281 | | // synchronized with locks. |
282 | | unsafe impl Sync for OwnedGuard<'_> {} |
283 | | |
284 | | // Safety: `OwnedGuard` owns its thread slot and is not tied to any |
285 | | // thread-locals. |
286 | | unsafe impl Send for OwnedGuard<'_> {} |
287 | | |
288 | | impl OwnedGuard<'_> { |
289 | | #[inline] |
290 | 0 | pub(crate) fn enter(collector: &Collector) -> OwnedGuard<'_> { |
291 | | // Create a thread slot that will last for the lifetime of this guard. |
292 | 0 | let thread = Thread::create(); |
293 | | |
294 | | // Safety: We have ownership of `thread` and have not shared it. |
295 | 0 | let reservation = unsafe { collector.raw.reservation(thread) }; |
296 | | |
297 | | // Safety: We have ownership of `reservation`. |
298 | 0 | unsafe { collector.raw.enter(reservation) }; |
299 | | |
300 | 0 | OwnedGuard { |
301 | 0 | collector, |
302 | 0 | thread, |
303 | 0 | reservation, |
304 | 0 | } |
305 | 0 | } |
306 | | } |
307 | | |
308 | | impl Guard for OwnedGuard<'_> { |
309 | | /// Refreshes the guard. |
310 | | #[inline] |
311 | 0 | fn refresh(&mut self) { |
312 | | // Safety: `self.reservation` is owned by the current thread. |
313 | 0 | let reservation = unsafe { &*self.reservation }; |
314 | 0 | unsafe { self.collector.raw.refresh(reservation) } |
315 | 0 | } |
316 | | |
317 | | /// Flush any retired values in the local batch. |
318 | | #[inline] |
319 | 0 | fn flush(&self) { |
320 | | // Safety: `self.reservation` is owned by the current thread. |
321 | 0 | let reservation = unsafe { &*self.reservation }; |
322 | 0 | let _lock = reservation.lock.lock().unwrap(); |
323 | | // Note that this does not actually retire any values, it just attempts to add |
324 | | // the batch to any active reservations lists, including ours. |
325 | | // |
326 | | // Safety: We hold the lock and so have unique access to the batch. |
327 | 0 | unsafe { self.collector.raw.try_retire_batch(self.thread) } |
328 | 0 | } |
329 | | |
330 | | /// Returns the collector this guard was created from. |
331 | | #[inline] |
332 | 0 | fn collector(&self) -> &Collector { |
333 | 0 | self.collector |
334 | 0 | } |
335 | | |
336 | | /// Returns a numeric identifier for the current thread. |
337 | | #[inline] |
338 | 0 | fn thread_id(&self) -> usize { |
339 | | // We can't return the ID of our thread slot because `OwnedGuard` is `Send` so |
340 | | // the ID is not uniquely tied to the current thread. We also can't |
341 | | // return the OS thread ID because it might conflict with our thread |
342 | | // IDs, so we have to get/create the current thread. |
343 | 0 | Thread::current().id |
344 | 0 | } |
345 | | |
346 | | /// Retires a value, running `reclaim` when no threads hold a reference to |
347 | | /// it. |
348 | | #[inline] |
349 | 0 | unsafe fn defer_retire<T>(&self, ptr: *mut T, reclaim: unsafe fn(*mut T, &Collector)) { |
350 | | // Safety: `self.reservation` is owned by the current thread. |
351 | 0 | let reservation = unsafe { &*self.reservation }; |
352 | 0 | let _lock = reservation.lock.lock().unwrap(); |
353 | | |
354 | | // Safety: |
355 | | // - We hold the lock and so have unique access to the batch. |
356 | | // - The validity of the pointer is guaranteed by the caller. |
357 | 0 | unsafe { self.collector.raw.add(ptr, reclaim, self.thread) } |
358 | 0 | } |
359 | | } |
360 | | |
361 | | impl Drop for OwnedGuard<'_> { |
362 | | #[inline] |
363 | 0 | fn drop(&mut self) { |
364 | | // Safety: `self.reservation` is owned by the current thread. |
365 | 0 | let reservation = unsafe { &*self.reservation }; |
366 | | |
367 | | // Safety: `self.thread` is an owned thread. |
368 | 0 | unsafe { self.collector.raw.leave(reservation) }; |
369 | | |
370 | | // Safety: We are in `drop` and never share `self.thread`. |
371 | 0 | unsafe { Thread::free(self.thread.id) }; |
372 | 0 | } |
373 | | } |