urcu/rcu/
callback.rs

1use std::ffi::c_void;
2use std::marker::PhantomData;
3use std::ptr::NonNull;
4
5use container_of::container_of;
6use urcu_sys::RcuHead;
7
8/// This trait defines a callback to be invoked after the next RCU grace period.
9///
10/// #### Implementation
11///
12/// Each flavor have a RCU linked list of `(callback, head)` pointers. Each RCU
13/// threads can queue callbacks in this list. A helper thread will pop callbacks
14/// and execute them with `callback(head)`.
15///
16/// #### Safety
17///
18/// When [`RcuCall::configure`] is called, you must deliberately leak your type
19/// (e.g. [`Box::into_raw`]) to prevent the memory from being freed. Upon execution
20/// of the callback, you must get back ownership (e.g. [`Box::from_raw`]) and properly
21/// free up memory. For an example, see [`RcuCallFn`].
22///
23/// Unlike [`RcuDefer`], we resulting pointer must be an [`RcuHead`] inside
24/// your data. You can use [`container_of!`] to get back the type implementing this
25/// trait.
26pub unsafe trait RcuCall {
27    /// Configures the callback for execution.
28    fn configure<F>(self: Box<Self>, func: F)
29    where
30        F: FnOnce(NonNull<RcuHead>, unsafe extern "C" fn(head: *mut RcuHead));
31}
32
33/// Defines a callback executed after the next RCU grace period.
34pub struct RcuCallFn<F> {
35    func: F,
36    head: RcuHead,
37}
38
39impl<F> RcuCallFn<F> {
40    /// Create a simple RCU callback.
41    pub fn new(func: F) -> Box<Self> {
42        Box::new(Self {
43            func,
44            head: Default::default(),
45        })
46    }
47
48    unsafe extern "C" fn rcu_callback(head_ptr: *mut RcuHead)
49    where
50        F: FnOnce(),
51    {
52        // SAFETY: The pointers should always be valid.
53        let node = Box::from_raw(container_of!(head_ptr, Self, head));
54
55        (node.func)();
56    }
57}
58
59/// #### Safety
60///
61/// The memory of [`Box<Self>`] is properly reclaimed upon the RCU callback.
62unsafe impl<F> RcuCall for RcuCallFn<F>
63where
64    F: FnOnce(),
65{
66    fn configure<P>(self: Box<Self>, func: P)
67    where
68        P: FnOnce(NonNull<RcuHead>, unsafe extern "C" fn(head: *mut RcuHead)),
69    {
70        let node_ptr = Box::into_raw(self);
71        let node = unsafe { &mut *node_ptr };
72
73        unsafe {
74            func(NonNull::new_unchecked(&mut node.head), Self::rcu_callback);
75        }
76    }
77}
78
79/// #### Safety
80///
81/// The callback can be sent to another thread if the reference implements [`Send`].
82unsafe impl<F> Send for RcuCallFn<F> where F: Send {}
83
84/// This trait defines a callback to be invoked after the next RCU grace period.
85///
86/// #### Implementation
87///
88/// Each RCU thread have an array of `(callback, data)` pointers. When the next RCU
89/// grace period finishes, the thread goes over each of its entry and execute
90/// `callback(data)`.
91///
92/// #### Safety
93///
94/// When [`RcuDefer::configure`] is called, you must deliberately leak your type
95/// (e.g. [`Box::into_raw`]) to prevent the memory from being freed. Upon execution
96/// of the callback, you must get back ownership (e.g. [`Box::from_raw`]) and properly
97/// free up memory. For an example, see [`RcuDeferFn`].
98pub unsafe trait RcuDefer {
99    /// Configures the callback for execution.
100    fn configure<F>(self: Box<Self>, func: F)
101    where
102        F: FnOnce(NonNull<c_void>, unsafe extern "C" fn(head: *mut c_void));
103}
104
105/// Defines a defer callback executed after the next RCU grace period.
106pub struct RcuDeferFn<F, C> {
107    func: F,
108    // Also prevents Send+Sync auto-trait implementations.
109    _context: PhantomData<*mut C>,
110}
111
112/// #### Safety
113///
114/// The memory of [`Box<Self>`] is properly reclaimed upon the RCU callback.
115impl<F, C> RcuDeferFn<F, C> {
116    /// Creates a callback.
117    pub fn new(func: F) -> Box<Self> {
118        Box::new(Self {
119            func,
120            _context: PhantomData,
121        })
122    }
123
124    unsafe extern "C" fn callback(ptr: *mut c_void)
125    where
126        F: FnOnce(),
127    {
128        // SAFETY: The pointers should always be valid.
129        let node = Box::from_raw(ptr as *mut Self);
130
131        (node.func)();
132    }
133}
134
135unsafe impl<F, C> RcuDefer for RcuDeferFn<F, C>
136where
137    F: FnOnce(),
138{
139    fn configure<P>(self: Box<Self>, func: P)
140    where
141        P: FnOnce(NonNull<c_void>, unsafe extern "C" fn(head: *mut c_void)),
142    {
143        let ptr = Box::into_raw(self) as *mut c_void;
144
145        // SAFETY: The pointer is never null.
146        unsafe { func(NonNull::new_unchecked(ptr), Self::callback) }
147    }
148}