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}