@@ -9,7 +9,7 @@ use crate::{bindings, sync::rcu};
9
9
use core:: {
10
10
cell:: UnsafeCell ,
11
11
marker:: PhantomData ,
12
- mem:: ManuallyDrop ,
12
+ mem:: MaybeUninit ,
13
13
ops:: Deref ,
14
14
ptr:: drop_in_place,
15
15
sync:: atomic:: { AtomicBool , Ordering } ,
@@ -63,32 +63,30 @@ use core::{
63
63
/// v.revoke();
64
64
/// assert_eq!(add_two(&v), None);
65
65
/// ```
66
- pub struct Revocable < T : ? Sized > {
66
+ pub struct Revocable < T > {
67
67
is_available : AtomicBool ,
68
- data : ManuallyDrop < UnsafeCell < T > > ,
68
+ data : MaybeUninit < UnsafeCell < T > > ,
69
69
}
70
70
71
71
// SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the
72
72
// functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that
73
73
// this isn't supported by the wrapped object.
74
- unsafe impl < T : ? Sized + Send > Send for Revocable < T > { }
74
+ unsafe impl < T : Send > Send for Revocable < T > { }
75
75
76
76
// SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send`
77
77
// from the wrapped object as well because of `Revocable::revoke`, which can trigger the `Drop`
78
78
// implementation of the wrapped object from an arbitrary thread.
79
- unsafe impl < T : ? Sized + Sync + Send > Sync for Revocable < T > { }
79
+ unsafe impl < T : Sync + Send > Sync for Revocable < T > { }
80
80
81
81
impl < T > Revocable < T > {
82
82
/// Creates a new revocable instance of the given data.
83
83
pub const fn new ( data : T ) -> Self {
84
84
Self {
85
85
is_available : AtomicBool :: new ( true ) ,
86
- data : ManuallyDrop :: new ( UnsafeCell :: new ( data) ) ,
86
+ data : MaybeUninit :: new ( UnsafeCell :: new ( data) ) ,
87
87
}
88
88
}
89
- }
90
89
91
- impl < T : ?Sized > Revocable < T > {
92
90
/// Tries to access the \[revocable\] wrapped object.
93
91
///
94
92
/// Returns `None` if the object has been revoked and is therefore no longer accessible.
@@ -99,7 +97,9 @@ impl<T: ?Sized> Revocable<T> {
99
97
pub fn try_access ( & self ) -> Option < RevocableGuard < ' _ , T > > {
100
98
let guard = rcu:: read_lock ( ) ;
101
99
if self . is_available . load ( Ordering :: Relaxed ) {
102
- Some ( RevocableGuard :: new ( self . data . get ( ) , guard) )
100
+ // SAFETY: Since `self.is_available` is true, data is initialised and has to remain
101
+ // valid because the RCU read side lock prevents it from being dropped.
102
+ Some ( unsafe { RevocableGuard :: new ( self . data . assume_init_ref ( ) . get ( ) , guard) } )
103
103
} else {
104
104
None
105
105
}
@@ -115,8 +115,9 @@ impl<T: ?Sized> Revocable<T> {
115
115
/// object.
116
116
pub fn try_access_with_guard < ' a > ( & ' a self , _guard : & ' a rcu:: Guard ) -> Option < & ' a T > {
117
117
if self . is_available . load ( Ordering :: Relaxed ) {
118
- // SAFETY: Given that the RCU read side lock is held, data has to remain valid.
119
- Some ( unsafe { & * self . data . get ( ) } )
118
+ // SAFETY: Since `self.is_available` is true, data is initialised and has to remain
119
+ // valid because the RCU read side lock prevents it from being dropped.
120
+ Some ( unsafe { & * self . data . assume_init_ref ( ) . get ( ) } )
120
121
} else {
121
122
None
122
123
}
@@ -139,20 +140,20 @@ impl<T: ?Sized> Revocable<T> {
139
140
140
141
// SAFETY: We know `self.data` is valid because only one CPU can succeed the
141
142
// `compare_exchange` above that takes `is_available` from `true` to `false`.
142
- unsafe { drop_in_place ( self . data . get ( ) ) } ;
143
+ unsafe { drop_in_place ( self . data . assume_init_ref ( ) . get ( ) ) } ;
143
144
}
144
145
}
145
146
}
146
147
147
- impl < T : ? Sized > Drop for Revocable < T > {
148
+ impl < T > Drop for Revocable < T > {
148
149
fn drop ( & mut self ) {
149
150
// Drop only if the data hasn't been revoked yet (in which case it has already been
150
151
// dropped).
151
152
if * self . is_available . get_mut ( ) {
152
153
// SAFETY: We know `self.data` is valid because no other CPU has changed
153
154
// `is_available` to `false` yet, and no other CPU can do it anymore because this CPU
154
155
// holds the only reference (mutable) to `self` now.
155
- unsafe { drop_in_place ( self . data . get ( ) ) } ;
156
+ unsafe { drop_in_place ( self . data . assume_init_ref ( ) . get ( ) ) } ;
156
157
}
157
158
}
158
159
}
@@ -165,13 +166,13 @@ impl<T: ?Sized> Drop for Revocable<T> {
165
166
/// # Invariants
166
167
///
167
168
/// The RCU read-side lock is held while the guard is alive.
168
- pub struct RevocableGuard < ' a , T : ? Sized > {
169
+ pub struct RevocableGuard < ' a , T > {
169
170
data_ref : * const T ,
170
171
_rcu_guard : rcu:: Guard ,
171
172
_p : PhantomData < & ' a ( ) > ,
172
173
}
173
174
174
- impl < T : ? Sized > RevocableGuard < ' _ , T > {
175
+ impl < T > RevocableGuard < ' _ , T > {
175
176
fn new ( data_ref : * const T , rcu_guard : rcu:: Guard ) -> Self {
176
177
Self {
177
178
data_ref,
@@ -181,7 +182,7 @@ impl<T: ?Sized> RevocableGuard<'_, T> {
181
182
}
182
183
}
183
184
184
- impl < T : ? Sized > Deref for RevocableGuard < ' _ , T > {
185
+ impl < T > Deref for RevocableGuard < ' _ , T > {
185
186
type Target = T ;
186
187
187
188
fn deref ( & self ) -> & Self :: Target {
0 commit comments