crossbeam_epoch/sync/list.rs
1//! Lock-free intrusive linked list.
2//!
3//! Ideas from Michael. High Performance Dynamic Lock-Free Hash Tables and List-Based Sets. SPAA
4//! 2002. <http://dl.acm.org/citation.cfm?id=564870.564881>
5
6use core::marker::PhantomData;
7use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
8
9use crate::{unprotected, Atomic, Guard, Shared};
10
11/// An entry in a linked list.
12///
13/// An Entry is accessed from multiple threads, so it would be beneficial to put it in a different
14/// cache-line than thread-local data in terms of performance.
15#[derive(Debug)]
16pub(crate) struct Entry {
17 /// The next entry in the linked list.
18 /// If the tag is 1, this entry is marked as deleted.
19 next: Atomic<Entry>,
20}
21
22/// Implementing this trait asserts that the type `T` can be used as an element in the intrusive
23/// linked list defined in this module. `T` has to contain (or otherwise be linked to) an instance
24/// of `Entry`.
25///
26/// # Example
27///
28/// ```ignore
29/// struct A {
30/// entry: Entry,
31/// data: usize,
32/// }
33///
34/// impl IsElement<A> for A {
35/// fn entry_of(a: &A) -> &Entry {
36/// let entry_ptr = ((a as usize) + offset_of!(A, entry)) as *const Entry;
37/// unsafe { &*entry_ptr }
38/// }
39///
40/// unsafe fn element_of(entry: &Entry) -> &T {
41/// let elem_ptr = ((entry as usize) - offset_of!(A, entry)) as *const T;
42/// &*elem_ptr
43/// }
44///
45/// unsafe fn finalize(entry: &Entry, guard: &Guard) {
46/// guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _));
47/// }
48/// }
49/// ```
50///
51/// This trait is implemented on a type separate from `T` (although it can be just `T`), because
52/// one type might be placeable into multiple lists, in which case it would require multiple
53/// implementations of `IsElement`. In such cases, each struct implementing `IsElement<T>`
54/// represents a distinct `Entry` in `T`.
55///
56/// For example, we can insert the following struct into two lists using `entry1` for one
57/// and `entry2` for the other:
58///
59/// ```ignore
60/// struct B {
61/// entry1: Entry,
62/// entry2: Entry,
63/// data: usize,
64/// }
65/// ```
66///
67pub(crate) trait IsElement<T> {
68 /// Returns a reference to this element's `Entry`.
69 fn entry_of(_: &T) -> &Entry;
70
71 /// Given a reference to an element's entry, returns that element.
72 ///
73 /// ```ignore
74 /// let elem = ListElement::new();
75 /// assert_eq!(elem.entry_of(),
76 /// unsafe { ListElement::element_of(elem.entry_of()) } );
77 /// ```
78 ///
79 /// # Safety
80 ///
81 /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance
82 /// of the element type (`T`).
83 unsafe fn element_of(_: &Entry) -> &T;
84
85 /// The function that is called when an entry is unlinked from list.
86 ///
87 /// # Safety
88 ///
89 /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance
90 /// of the element type (`T`).
91 unsafe fn finalize(_: &Entry, _: &Guard);
92}
93
94/// A lock-free, intrusive linked list of type `T`.
95#[derive(Debug)]
96pub(crate) struct List<T, C: IsElement<T> = T> {
97 /// The head of the linked list.
98 head: Atomic<Entry>,
99
100 /// The phantom data for using `T` and `C`.
101 _marker: PhantomData<(T, C)>,
102}
103
104/// An iterator used for retrieving values from the list.
105pub(crate) struct Iter<'g, T, C: IsElement<T>> {
106 /// The guard that protects the iteration.
107 guard: &'g Guard,
108
109 /// Pointer from the predecessor to the current entry.
110 pred: &'g Atomic<Entry>,
111
112 /// The current entry.
113 curr: Shared<'g, Entry>,
114
115 /// The list head, needed for restarting iteration.
116 head: &'g Atomic<Entry>,
117
118 /// Logically, we store a borrow of an instance of `T` and
119 /// use the type information from `C`.
120 _marker: PhantomData<(&'g T, C)>,
121}
122
123/// An error that occurs during iteration over the list.
124#[derive(PartialEq, Debug)]
125pub(crate) enum IterError {
126 /// A concurrent thread modified the state of the list at the same place that this iterator
127 /// was inspecting. Subsequent iteration will restart from the beginning of the list.
128 Stalled,
129}
130
131impl Default for Entry {
132 /// Returns the empty entry.
133 fn default() -> Self {
134 Self {
135 next: Atomic::null(),
136 }
137 }
138}
139
140impl Entry {
141 /// Marks this entry as deleted, deferring the actual deallocation to a later iteration.
142 ///
143 /// # Safety
144 ///
145 /// The entry should be a member of a linked list, and it should not have been deleted.
146 /// It should be safe to call `C::finalize` on the entry after the `guard` is dropped, where `C`
147 /// is the associated helper for the linked list.
148 pub(crate) unsafe fn delete(&self, guard: &Guard) {
149 self.next.fetch_or(1, Release, guard);
150 }
151}
152
153impl<T, C: IsElement<T>> List<T, C> {
154 /// Returns a new, empty linked list.
155 pub(crate) fn new() -> Self {
156 Self {
157 head: Atomic::null(),
158 _marker: PhantomData,
159 }
160 }
161
162 /// Inserts `entry` into the head of the list.
163 ///
164 /// # Safety
165 ///
166 /// You should guarantee that:
167 ///
168 /// - `container` is not null
169 /// - `container` is immovable, e.g. inside an `Owned`
170 /// - the same `Entry` is not inserted more than once
171 /// - the inserted object will be removed before the list is dropped
172 pub(crate) unsafe fn insert<'g>(&'g self, container: Shared<'g, T>, guard: &'g Guard) {
173 // Insert right after head, i.e. at the beginning of the list.
174 let to = &self.head;
175 // Get the intrusively stored Entry of the new element to insert.
176 let entry: &Entry = C::entry_of(container.deref());
177 // Make a Shared ptr to that Entry.
178 let entry_ptr = Shared::from(entry as *const _);
179 // Read the current successor of where we want to insert.
180 let mut next = to.load(Relaxed, guard);
181
182 loop {
183 // Set the Entry of the to-be-inserted element to point to the previous successor of
184 // `to`.
185 entry.next.store(next, Relaxed);
186 match to.compare_exchange_weak(next, entry_ptr, Release, Relaxed, guard) {
187 Ok(_) => break,
188 // We lost the race or weak CAS failed spuriously. Update the successor and try
189 // again.
190 Err(err) => next = err.current,
191 }
192 }
193 }
194
195 /// Returns an iterator over all objects.
196 ///
197 /// # Caveat
198 ///
199 /// Every object that is inserted at the moment this function is called and persists at least
200 /// until the end of iteration will be returned. Since this iterator traverses a lock-free
201 /// linked list that may be concurrently modified, some additional caveats apply:
202 ///
203 /// 1. If a new object is inserted during iteration, it may or may not be returned.
204 /// 2. If an object is deleted during iteration, it may or may not be returned.
205 /// 3. The iteration may be aborted when it lost in a race condition. In this case, the winning
206 /// thread will continue to iterate over the same list.
207 pub(crate) fn iter<'g>(&'g self, guard: &'g Guard) -> Iter<'g, T, C> {
208 Iter {
209 guard,
210 pred: &self.head,
211 curr: self.head.load(Acquire, guard),
212 head: &self.head,
213 _marker: PhantomData,
214 }
215 }
216}
217
218impl<T, C: IsElement<T>> Drop for List<T, C> {
219 fn drop(&mut self) {
220 unsafe {
221 let guard = unprotected();
222 let mut curr = self.head.load(Relaxed, guard);
223 while let Some(c) = curr.as_ref() {
224 let succ = c.next.load(Relaxed, guard);
225 // Verify that all elements have been removed from the list.
226 assert_eq!(succ.tag(), 1);
227
228 C::finalize(curr.deref(), guard);
229 curr = succ;
230 }
231 }
232 }
233}
234
235impl<'g, T: 'g, C: IsElement<T>> Iterator for Iter<'g, T, C> {
236 type Item = Result<&'g T, IterError>;
237
238 fn next(&mut self) -> Option<Self::Item> {
239 while let Some(c) = unsafe { self.curr.as_ref() } {
240 let succ = c.next.load(Acquire, self.guard);
241
242 if succ.tag() == 1 {
243 // This entry was removed. Try unlinking it from the list.
244 let succ = succ.with_tag(0);
245
246 // The tag should always be zero, because removing a node after a logically deleted
247 // node leaves the list in an invalid state.
248 debug_assert!(self.curr.tag() == 0);
249
250 // Try to unlink `curr` from the list, and get the new value of `self.pred`.
251 let succ = match self
252 .pred
253 .compare_exchange(self.curr, succ, Acquire, Acquire, self.guard)
254 {
255 Ok(_) => {
256 // We succeeded in unlinking `curr`, so we have to schedule
257 // deallocation. Deferred drop is okay, because `list.delete()` can only be
258 // called if `T: 'static`.
259 unsafe {
260 C::finalize(self.curr.deref(), self.guard);
261 }
262
263 // `succ` is the new value of `self.pred`.
264 succ
265 }
266 Err(e) => {
267 // `e.current` is the current value of `self.pred`.
268 e.current
269 }
270 };
271
272 // If the predecessor node is already marked as deleted, we need to restart from
273 // `head`.
274 if succ.tag() != 0 {
275 self.pred = self.head;
276 self.curr = self.head.load(Acquire, self.guard);
277
278 return Some(Err(IterError::Stalled));
279 }
280
281 // Move over the removed by only advancing `curr`, not `pred`.
282 self.curr = succ;
283 continue;
284 }
285
286 // Move one step forward.
287 self.pred = &c.next;
288 self.curr = succ;
289
290 return Some(Ok(unsafe { C::element_of(c) }));
291 }
292
293 // We reached the end of the list.
294 None
295 }
296}
297
298#[cfg(all(test, not(crossbeam_loom)))]
299mod tests {
300 use super::*;
301 use crate::{Collector, Owned};
302 use crossbeam_utils::thread;
303 use std::sync::Barrier;
304 use std::vec::Vec;
305
306 impl IsElement<Entry> for Entry {
307 fn entry_of(entry: &Entry) -> &Entry {
308 entry
309 }
310
311 unsafe fn element_of(entry: &Entry) -> &Entry {
312 entry
313 }
314
315 unsafe fn finalize(entry: &Entry, guard: &Guard) {
316 guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _));
317 }
318 }
319
320 /// Checks whether the list retains inserted elements
321 /// and returns them in the correct order.
322 #[test]
323 fn insert() {
324 let collector = Collector::new();
325 let handle = collector.register();
326 let guard = handle.pin();
327
328 let l: List<Entry> = List::new();
329
330 let e1 = Owned::new(Entry::default()).into_shared(&guard);
331 let e2 = Owned::new(Entry::default()).into_shared(&guard);
332 let e3 = Owned::new(Entry::default()).into_shared(&guard);
333
334 unsafe {
335 l.insert(e1, &guard);
336 l.insert(e2, &guard);
337 l.insert(e3, &guard);
338 }
339
340 let mut iter = l.iter(&guard);
341 let maybe_e3 = iter.next();
342 assert!(maybe_e3.is_some());
343 assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
344 let maybe_e2 = iter.next();
345 assert!(maybe_e2.is_some());
346 assert!(maybe_e2.unwrap().unwrap() as *const Entry == e2.as_raw());
347 let maybe_e1 = iter.next();
348 assert!(maybe_e1.is_some());
349 assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
350 assert!(iter.next().is_none());
351
352 unsafe {
353 e1.as_ref().unwrap().delete(&guard);
354 e2.as_ref().unwrap().delete(&guard);
355 e3.as_ref().unwrap().delete(&guard);
356 }
357 }
358
359 /// Checks whether elements can be removed from the list and whether
360 /// the correct elements are removed.
361 #[test]
362 fn delete() {
363 let collector = Collector::new();
364 let handle = collector.register();
365 let guard = handle.pin();
366
367 let l: List<Entry> = List::new();
368
369 let e1 = Owned::new(Entry::default()).into_shared(&guard);
370 let e2 = Owned::new(Entry::default()).into_shared(&guard);
371 let e3 = Owned::new(Entry::default()).into_shared(&guard);
372 unsafe {
373 l.insert(e1, &guard);
374 l.insert(e2, &guard);
375 l.insert(e3, &guard);
376 e2.as_ref().unwrap().delete(&guard);
377 }
378
379 let mut iter = l.iter(&guard);
380 let maybe_e3 = iter.next();
381 assert!(maybe_e3.is_some());
382 assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
383 let maybe_e1 = iter.next();
384 assert!(maybe_e1.is_some());
385 assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
386 assert!(iter.next().is_none());
387
388 unsafe {
389 e1.as_ref().unwrap().delete(&guard);
390 e3.as_ref().unwrap().delete(&guard);
391 }
392
393 let mut iter = l.iter(&guard);
394 assert!(iter.next().is_none());
395 }
396
397 const THREADS: usize = 8;
398 const ITERS: usize = 512;
399
400 /// Contends the list on insert and delete operations to make sure they can run concurrently.
401 #[test]
402 fn insert_delete_multi() {
403 let collector = Collector::new();
404
405 let l: List<Entry> = List::new();
406 let b = Barrier::new(THREADS);
407
408 thread::scope(|s| {
409 for _ in 0..THREADS {
410 s.spawn(|_| {
411 b.wait();
412
413 let handle = collector.register();
414 let guard: Guard = handle.pin();
415 let mut v = Vec::with_capacity(ITERS);
416
417 for _ in 0..ITERS {
418 let e = Owned::new(Entry::default()).into_shared(&guard);
419 v.push(e);
420 unsafe {
421 l.insert(e, &guard);
422 }
423 }
424
425 for e in v {
426 unsafe {
427 e.as_ref().unwrap().delete(&guard);
428 }
429 }
430 });
431 }
432 })
433 .unwrap();
434
435 let handle = collector.register();
436 let guard = handle.pin();
437
438 let mut iter = l.iter(&guard);
439 assert!(iter.next().is_none());
440 }
441
442 /// Contends the list on iteration to make sure that it can be iterated over concurrently.
443 #[test]
444 fn iter_multi() {
445 let collector = Collector::new();
446
447 let l: List<Entry> = List::new();
448 let b = Barrier::new(THREADS);
449
450 thread::scope(|s| {
451 for _ in 0..THREADS {
452 s.spawn(|_| {
453 b.wait();
454
455 let handle = collector.register();
456 let guard: Guard = handle.pin();
457 let mut v = Vec::with_capacity(ITERS);
458
459 for _ in 0..ITERS {
460 let e = Owned::new(Entry::default()).into_shared(&guard);
461 v.push(e);
462 unsafe {
463 l.insert(e, &guard);
464 }
465 }
466
467 let mut iter = l.iter(&guard);
468 for _ in 0..ITERS {
469 assert!(iter.next().is_some());
470 }
471
472 for e in v {
473 unsafe {
474 e.as_ref().unwrap().delete(&guard);
475 }
476 }
477 });
478 }
479 })
480 .unwrap();
481
482 let handle = collector.register();
483 let guard = handle.pin();
484
485 let mut iter = l.iter(&guard);
486 assert!(iter.next().is_none());
487 }
488}