urcu/rcu/
context.rs

1use std::cell::Cell;
2use std::marker::PhantomData;
3
4use crate::rcu::callback::{RcuCall, RcuDefer};
5use crate::rcu::flavor::RcuFlavor;
6use crate::rcu::guard::RcuGuard;
7use crate::rcu::poller::RcuPoller;
8use crate::utility::{PhantomUnsend, PhantomUnsync};
9
10/// This trait defines the per-thread RCU context.
11///
12/// #### Design
13///
14/// This trait exploits the borrowing rule of Rust.
15///
16/// > At any given time, you can have either one mutable reference (`&mut T`) or
17/// > any number of immutable references (`&T`).
18///
19/// By exploiting this rule, we can enforce that a thread never executes a RCU
20/// synchronization barrier at the same time as it holds a RCU read lock. For
21/// example, [`RcuReadContext::rcu_read_lock`] requires (`&self`), meaning we can
22/// nest as many read locks as we want. On the other hand, [`RcuContext::rcu_synchronize`]
23/// requires `&mut self`, meaning we can never call it while a read guard borrows
24/// `&self`.
25///
26/// #### Safety
27///
28/// You must enforce single context per thread for a specific RCU flavor.
29/// Failure to do so can lead to a deadlock if a thread acquires a RCU read lock
30/// from one context and tries to do a RCU syncronization from another context.
31pub unsafe trait RcuContext {
32    /// Defines an API for unchecked RCU primitives.
33    type Flavor: RcuFlavor;
34
35    /// Defines a grace period poller;
36    type Poller<'a>: RcuPoller + 'a
37    where
38        Self: 'a;
39
40    /// Waits until the RCU grace period is over.
41    ///
42    /// #### Note
43    ///
44    /// It cannot be called in a RCU critical section.
45    fn rcu_synchronize(&mut self);
46
47    /// Creates a RCU grace period poller.
48    ///
49    /// #### Note
50    ///
51    /// It may be called in a RCU critical section.
52    fn rcu_synchronize_poller(&self) -> Self::Poller<'_>;
53}
54
55/// This trait defines the per-thread RCU read context.
56///
57/// #### Safety
58///
59/// For callbacks (`rcu_call`), a barrier (`rcu_barrier`) should be executed
60/// before cleaning up the context. Failure to do so might results in memory
61/// leaks and object cleanups that don't happen.
62pub unsafe trait RcuReadContext: RcuContext {
63    /// Defines a guard for a RCU critical section.
64    type Guard<'a>: RcuGuard<Flavor = Self::Flavor> + 'a
65    where
66        Self: 'a;
67
68    /// Starts a RCU critical section.
69    ///
70    /// #### Note
71    ///
72    /// RCU critical sections may be nested.
73    fn rcu_read_lock(&self) -> Self::Guard<'_>;
74
75    /// Configures a callback to be called after the next RCU grace period is finished.
76    ///
77    /// #### Note
78    ///
79    /// The function will internally call [`RcuReadContext::rcu_read_lock`].
80    ///
81    /// The callback must be [`Send`] because it will be executed by an helper thread.
82    fn rcu_call<F>(&self, callback: Box<F>)
83    where
84        F: RcuCall + Send + 'static;
85}
86
87/// This trait defines the per-thread RCU defer context.
88///
89/// #### Safety
90///
91/// For deferred callbacks (`rcu_defer`), a barrier (`defer_barrier`) should be
92/// executed before cleaning up the context. Failure to do so might results in
93/// memory leaks and object cleanups that don't happen.
94pub unsafe trait RcuDeferContext: RcuContext {
95    /// Configures a callback to be called after the next RCU grace period is finished.
96    ///
97    /// #### Note
98    ///
99    /// The function might internally call [`RcuContext::rcu_synchronize`] and block.
100    ///
101    /// The callback is guaranteed to be executed on the current thread.
102    fn rcu_defer<F>(&mut self, callback: Box<F>)
103    where
104        F: RcuDefer;
105}
106
107macro_rules! define_rcu_context {
108    ($kind:ident, $context:ident, $flavor:ident, $guard:ident, $poller:ident) => {
109        #[doc = concat!("Defines a RCU context for the current thread (`liburcu-", stringify!($kind), "`).")]
110        ///
111        /// #### Note
112        ///
113        /// There can only be 1 instance per thread.
114        /// The thread will be registered upon creation.
115        /// It will be unregistered upon dropping.
116        pub struct $context<const READ: bool = false, const DEFER: bool = false>(
117            PhantomUnsend,
118            PhantomUnsync,
119        );
120
121        impl<const READ: bool, const DEFER: bool> $context<READ, DEFER> {
122            /// Creates the context instance.
123            ///
124            /// Only the first call will return a context.
125            /// Subsequent calls on the same thread will return nothing.
126            pub(crate) fn new() -> Option<Self> {
127                thread_local! {static RCU_CONTEXT: Cell<bool> = Cell::new(false)};
128
129                RCU_CONTEXT.with(|initialized| {
130                    if initialized.replace(true) {
131                        return None;
132                    }
133
134                    log::info!(
135                        "registering thread '{}' ({}) with RCU (liburcu-{})",
136                        std::thread::current().name().unwrap_or("<unnamed>"),
137                        unsafe { libc::gettid() },
138                        stringify!($kind),
139                    );
140
141                    // SAFETY: Can only be called once per thread.
142                    // SAFETY: It is the first RCU call for a thread.
143                    unsafe { $flavor::unchecked_rcu_init() };
144
145                    if READ {
146                        // SAFETY: The thread is initialized.
147                        // SAFETY: The thread is not read-registered.
148                        // SAFETY: The thread is read-unregistered at context's drop.
149                        unsafe { $flavor::unchecked_rcu_read_register_thread() };
150                    }
151
152                    if DEFER {
153                        // SAFETY: The thread is initialized.
154                        // SAFETY: The thread is not defer-registered.
155                        // SAFETY: The thread is read-unregistered at context's drop.
156                        unsafe { $flavor::unchecked_rcu_defer_register_thread() };
157                    }
158
159                    Some(Self(PhantomData, PhantomData))
160                })
161            }
162        }
163
164        impl<const READ: bool, const DEFER: bool> Drop for $context<READ, DEFER> {
165            fn drop(&mut self) {
166                log::info!(
167                    "unregistering thread '{}' ({}) with RCU (liburcu-{})",
168                    std::thread::current().name().unwrap_or("<unnamed>"),
169                    unsafe { libc::gettid() },
170                    stringify!($kind),
171                );
172
173                if DEFER {
174                    // SAFETY: The thread is initialized at context's creation.
175                    // SAFETY: The thread is defer-registered at context's creation.
176                    // SAFETY: The thread can't be in a RCU critical section if it's dropping.
177                    unsafe { $flavor::unchecked_rcu_defer_barrier() };
178
179                    // SAFETY: The thread is initialized at context's creation.
180                    // SAFETY: The thread is defer-registered at context's creation.
181                    unsafe { $flavor::unchecked_rcu_defer_unregister_thread() };
182                }
183
184                if READ {
185                    // SAFETY: The thread is initialized at context's creation.
186                    // SAFETY: The thread is read-registered at context's creation.
187                    unsafe { $flavor::unchecked_rcu_call_barrier() };
188
189                    // SAFETY: The thread is initialized at context's creation.
190                    // SAFETY: The thread is read-registered at context's creation.
191                    unsafe { $flavor::unchecked_rcu_read_unregister_thread() };
192                }
193            }
194        }
195
196        /// #### Safety
197        ///
198        /// There can only be 1 instance per thread.
199        unsafe impl<const READ: bool, const DEFER: bool> RcuContext for $context<READ, DEFER> {
200            type Flavor = $flavor;
201
202            type Poller<'a> = $poller<'a>;
203
204            fn rcu_synchronize(&mut self) {
205                // SAFETY: The thread is initialized at context's creation.
206                // SAFETY: The thread cannot be in a critical section because of `&mut self`.
207                unsafe { $flavor::unchecked_rcu_synchronize() };
208            }
209
210            fn rcu_synchronize_poller(&self) -> Self::Poller<'_> {
211                $poller::new(self)
212            }
213        }
214
215        /// #### Safety
216        ///
217        /// `call_rcu` barrier is called before cleanups.
218        unsafe impl<const DEFER: bool> RcuReadContext for $context<true, DEFER> {
219            type Guard<'a> = $guard<'a>;
220
221            fn rcu_read_lock(&self) -> Self::Guard<'_> {
222                $guard::<'_>::new(self)
223            }
224
225            fn rcu_call<F>(&self, callback: Box<F>)
226            where
227                F: RcuCall + Send + 'static,
228            {
229                callback.configure(|mut head, func| {
230                    // SAFETY: The thread is initialized at context's creation.
231                    // SAFETY: The thread is read-registered at context's creation.
232                    // SAFETY: The thread executes a call-barrier at context's drop.
233                    // SAFETY: The pointers validity is guaranteed by `RcuCall`.
234                    unsafe { $flavor::unchecked_rcu_call(Some(func), head.as_mut()) };
235                });
236            }
237        }
238
239        /// #### Safety
240        ///
241        /// `defer_rcu` barrier is called before cleanups.
242        unsafe impl<const READ: bool> RcuDeferContext for $context<READ, true> {
243            fn rcu_defer<F>(&mut self, callback: Box<F>)
244            where
245                F: RcuDefer,
246            {
247                callback.configure(|mut ptr, func| {
248                    // SAFETY: The thread is initialized at context's creation.
249                    // SAFETY: The thread is defer-registered at context's creation.
250                    // SAFETY: The thread executes a defer-barrier at context's drop.
251                    // SAFETY: The thread cannot be in a critical section because of `&mut self`.
252                    // SAFETY: The pointers validity is guaranteed by `RcuDefer`.
253                    unsafe { $flavor::unchecked_rcu_defer_call(Some(func), ptr.as_mut()) };
254                });
255            }
256        }
257    };
258}
259
260#[cfg(feature = "flavor-bp")]
261mod bp {
262    use super::*;
263
264    use crate::rcu::flavor::RcuFlavorBp;
265    use crate::rcu::guard::RcuGuardBp;
266    use crate::rcu::poller::RcuPollerBp;
267
268    define_rcu_context!(bp, RcuContextBp, RcuFlavorBp, RcuGuardBp, RcuPollerBp);
269}
270
271#[cfg(feature = "flavor-mb")]
272mod mb {
273    use super::*;
274
275    use crate::rcu::flavor::RcuFlavorMb;
276    use crate::rcu::guard::RcuGuardMb;
277    use crate::rcu::poller::RcuPollerMb;
278
279    define_rcu_context!(mb, RcuContextMb, RcuFlavorMb, RcuGuardMb, RcuPollerMb);
280}
281
282#[cfg(feature = "flavor-memb")]
283mod memb {
284    use super::*;
285
286    use crate::rcu::flavor::RcuFlavorMemb;
287    use crate::rcu::guard::RcuGuardMemb;
288    use crate::rcu::poller::RcuPollerMemb;
289
290    define_rcu_context!(
291        memb,
292        RcuContextMemb,
293        RcuFlavorMemb,
294        RcuGuardMemb,
295        RcuPollerMemb
296    );
297}
298
299#[cfg(feature = "flavor-qsbr")]
300mod qsbr {
301    use super::*;
302
303    use crate::rcu::flavor::RcuFlavorQsbr;
304    use crate::rcu::guard::RcuGuardQsbr;
305    use crate::rcu::poller::RcuPollerQsbr;
306
307    define_rcu_context!(
308        qsbr,
309        RcuContextQsbr,
310        RcuFlavorQsbr,
311        RcuGuardQsbr,
312        RcuPollerQsbr
313    );
314}
315
316#[cfg(feature = "flavor-bp")]
317pub use bp::*;
318
319#[cfg(feature = "flavor-mb")]
320pub use mb::*;
321
322#[cfg(feature = "flavor-memb")]
323pub use memb::*;
324
325#[cfg(feature = "flavor-qsbr")]
326pub use qsbr::*;
327
328mod asserts {
329    use static_assertions::assert_not_impl_all;
330
331    #[cfg(feature = "flavor-bp")]
332    mod bp {
333        use super::*;
334
335        use crate::rcu::context::bp::RcuContextBp;
336
337        assert_not_impl_all!(RcuContextBp: Send);
338        assert_not_impl_all!(RcuContextBp: Sync);
339    }
340
341    #[cfg(feature = "flavor-mb")]
342    mod mb {
343        use super::*;
344
345        use crate::rcu::context::mb::RcuContextMb;
346
347        assert_not_impl_all!(RcuContextMb: Send);
348        assert_not_impl_all!(RcuContextMb: Sync);
349    }
350
351    #[cfg(feature = "flavor-memb")]
352    mod memb {
353        use super::*;
354
355        use crate::rcu::context::memb::RcuContextMemb;
356
357        assert_not_impl_all!(RcuContextMemb: Send);
358        assert_not_impl_all!(RcuContextMemb: Sync);
359    }
360
361    #[cfg(feature = "flavor-qsbr")]
362    mod qsbr {
363        use super::*;
364
365        use crate::rcu::context::qsbr::RcuContextQsbr;
366
367        assert_not_impl_all!(RcuContextQsbr: Send);
368        assert_not_impl_all!(RcuContextQsbr: Sync);
369    }
370}