@@ -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