5
5
//! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence
6
6
//! of a [`RevocableGuard`] ensures that objects remain valid.
7
7
8
- use crate :: bindings;
8
+ use crate :: { bindings, sync :: rcu } ;
9
9
use core:: {
10
10
cell:: UnsafeCell ,
11
11
marker:: PhantomData ,
@@ -40,6 +40,29 @@ use core::{
40
40
/// v.revoke();
41
41
/// assert_eq!(add_two(&v), None);
42
42
/// ```
43
+ ///
44
+ /// Sample example as above, but explicitly using the rcu read side lock.
45
+ ///
46
+ /// ```
47
+ /// # use kernel::revocable::Revocable;
48
+ /// use kernel::sync::rcu;
49
+ ///
50
+ /// struct Example {
51
+ /// a: u32,
52
+ /// b: u32,
53
+ /// }
54
+ ///
55
+ /// fn add_two(v: &Revocable<Example>) -> Option<u32> {
56
+ /// let guard = rcu::read_lock();
57
+ /// let e = v.try_access_with_guard(&guard)?;
58
+ /// Some(e.a + e.b)
59
+ /// }
60
+ ///
61
+ /// let v = Revocable::new(Example { a: 10, b: 20 });
62
+ /// assert_eq!(add_two(&v), Some(30));
63
+ /// v.revoke();
64
+ /// assert_eq!(add_two(&v), None);
65
+ /// ```
43
66
pub struct Revocable < T : ?Sized > {
44
67
is_available : AtomicBool ,
45
68
data : ManuallyDrop < UnsafeCell < T > > ,
@@ -57,7 +80,7 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Revocable<T> {}
57
80
58
81
impl < T > Revocable < T > {
59
82
/// Creates a new revocable instance of the given data.
60
- pub fn new ( data : T ) -> Self {
83
+ pub const fn new ( data : T ) -> Self {
61
84
Self {
62
85
is_available : AtomicBool :: new ( true ) ,
63
86
data : ManuallyDrop :: new ( UnsafeCell :: new ( data) ) ,
@@ -74,9 +97,26 @@ impl<T: ?Sized> Revocable<T> {
74
97
/// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep
75
98
/// because another CPU may be waiting to complete the revocation of this object.
76
99
pub fn try_access ( & self ) -> Option < RevocableGuard < ' _ , T > > {
77
- let guard = RevocableGuard :: new ( self . data . get ( ) ) ;
100
+ let guard = rcu:: read_lock ( ) ;
101
+ if self . is_available . load ( Ordering :: Relaxed ) {
102
+ Some ( RevocableGuard :: new ( self . data . get ( ) , guard) )
103
+ } else {
104
+ None
105
+ }
106
+ }
107
+
108
+ /// Tries to access the \[revocable\] wrapped object.
109
+ ///
110
+ /// Returns `None` if the object has been revoked and is therefore no longer accessible.
111
+ ///
112
+ /// Returns a shared reference to the object otherwise; the object is guaranteed to
113
+ /// remain accessible while the rcu read side guard is alive. In such cases, callers are not
114
+ /// allowed to sleep because another CPU may be waiting to complete the revocation of this
115
+ /// object.
116
+ pub fn try_access_with_guard < ' a > ( & ' a self , _guard : & ' a rcu:: Guard ) -> Option < & ' a T > {
78
117
if self . is_available . load ( Ordering :: Relaxed ) {
79
- Some ( guard)
118
+ // SAFETY: Given that the RCU read side lock is held, data has to remain valid.
119
+ Some ( unsafe { & * self . data . get ( ) } )
80
120
} else {
81
121
None
82
122
}
@@ -127,29 +167,20 @@ impl<T: ?Sized> Drop for Revocable<T> {
127
167
/// The RCU read-side lock is held while the guard is alive.
128
168
pub struct RevocableGuard < ' a , T : ?Sized > {
129
169
data_ref : * const T ,
170
+ _rcu_guard : rcu:: Guard ,
130
171
_p : PhantomData < & ' a ( ) > ,
131
172
}
132
173
133
174
impl < T : ?Sized > RevocableGuard < ' _ , T > {
134
- fn new ( data_ref : * const T ) -> Self {
135
- // SAFETY: Just an FFI call, there are no further requirements.
136
- unsafe { bindings:: rcu_read_lock ( ) } ;
137
-
138
- // INVARIANTS: The RCU read-side lock was just acquired.
175
+ fn new ( data_ref : * const T , rcu_guard : rcu:: Guard ) -> Self {
139
176
Self {
140
177
data_ref,
178
+ _rcu_guard : rcu_guard,
141
179
_p : PhantomData ,
142
180
}
143
181
}
144
182
}
145
183
146
- impl < T : ?Sized > Drop for RevocableGuard < ' _ , T > {
147
- fn drop ( & mut self ) {
148
- // SAFETY: By the type invariants, we know that we hold the RCU read-side lock.
149
- unsafe { bindings:: rcu_read_unlock ( ) } ;
150
- }
151
- }
152
-
153
184
impl < T : ?Sized > Deref for RevocableGuard < ' _ , T > {
154
185
type Target = T ;
155
186
0 commit comments