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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Epoch-based reclamation.
//!
//! The epoch consensus algorithm and the use of memory barriers and RMW semantics are similar to
//! that of [`crossbeam_epoch`](https://docs.rs/crossbeam-epoch/), however the API set is vastly
//! different, for instance, `unsafe` blocks are not required to read an instance subject to EBR.
//!
//! # Examples
//!
//! The following code shows [`Arc`], [`AtomicArc`], [`Barrier`], [`Ptr`], and [`Tag`] usage.
//!
//! ```
//! use scc::ebr::{suspend, Arc, AtomicArc, Barrier, Ptr, Tag};
//! use std::sync::atomic::Ordering::Relaxed;
//!
//! // `atomic_arc` holds a strong reference to `17`.
//! let atomic_arc: AtomicArc<usize> = AtomicArc::new(17);
//!
//! // `barrier` prevents the garbage collector from dropping reachable instances.
//! let barrier: Barrier = Barrier::new();
//!
//! // `ptr` cannot outlive `barrier`.
//! let mut ptr: Ptr<usize> = atomic_arc.load(Relaxed, &barrier);
//! assert_eq!(*ptr.as_ref().unwrap(), 17);
//!
//! // `atomic_arc` can be tagged.
//! atomic_arc.update_tag_if(Tag::First, |p| p.tag() == Tag::None, Relaxed, Relaxed);
//!
//! // `ptr` is not tagged, so CAS fails.
//! assert!(atomic_arc.compare_exchange(
//! ptr,
//! (Some(Arc::new(18)), Tag::First),
//! Relaxed,
//! Relaxed,
//! &barrier).is_err());
//!
//! // `ptr` can be tagged.
//! ptr.set_tag(Tag::First);
//!
//! // The result of CAS is a handle to the instance that `atomic_arc` previously owned.
//! let prev: Arc<usize> = atomic_arc.compare_exchange(
//! ptr,
//! (Some(Arc::new(18)), Tag::Second),
//! Relaxed,
//! Relaxed,
//! &barrier).unwrap().0.unwrap();
//! assert_eq!(*prev, 17);
//!
//! // `17` will be garbage-collected later.
//! drop(prev);
//!
//! // `ebr::AtomicArc` can be converted into `ebr::Arc`.
//! let arc: Arc<usize> = atomic_arc.try_into_arc(Relaxed).unwrap();
//! assert_eq!(*arc, 18);
//!
//! // `18` will be garbage-collected later.
//! drop(arc);
//!
//! // `17` is still valid as `barrier` keeps the garbage collector from dropping it.
//! assert_eq!(*ptr.as_ref().unwrap(), 17);
//!
//! // Execution of a closure can be deferred until all the current readers are gone.
//! barrier.defer_execute(|| println!("deferred"));
//! drop(barrier);
//!
//! // The closure will be repeatedly invoked until it returns `true`.
//! let barrier = Barrier::new();
//! let mut data = 3;
//! barrier.defer_incremental_execute(move || {
//! if data == 0 {
//! return true;
//! }
//! data -= 1;
//! false
//! });
//! drop(barrier);
//!
//! // If the thread is expected to lie dormant for a while, call `suspend()` to allow other
//! // threads to reclaim its own retired instances.
//! suspend();
//! ```
pub use Arc;
pub use AtomicArc;
pub use Barrier;
pub use Collectible;
pub use Ptr;
pub use Tag;
/// Suspends the garbage collector of the current thread.
///
/// If returns `false` if there is an active [`Barrier`] in the thread. Otherwise, it passes all
/// its garbage instances to a free flowing garbage container that can be cleaned up by other
/// threads.
///
/// # Examples
///
/// ```
/// use scc::ebr::{suspend, Arc, Barrier};
///
/// assert!(suspend());
///
/// {
/// let arc: Arc<usize> = Arc::new(47);
/// let barrier = Barrier::new();
/// arc.release(&barrier);
/// assert!(!suspend());
/// }
///
/// assert!(suspend());
///
/// let new_arc: Arc<usize> = Arc::new(17);
/// let barrier = Barrier::new();
/// new_arc.release(&barrier);
/// ```