7
7
8
8
use std:: ops:: { Deref , DerefMut } ;
9
9
use std:: ptr:: NonNull ;
10
- use std:: sync:: Mutex ;
10
+ use std:: sync:: { Mutex , MutexGuard } ;
11
11
12
12
use crate :: CellState ;
13
13
@@ -69,8 +69,9 @@ impl<'a, T> Drop for RefGuard<'a, T> {
69
69
70
70
/// Wraps a mutably borrowed value of type `T`.
71
71
///
72
- /// This prevents all other borrows of `value`, unless the `&mut` reference handed out from this guard is
73
- /// made inaccessible by a call to [`GdCell::make_inaccessible()`](crate::GdCell::make_inaccessible).
72
+ /// This prevents all other borrows of `value` while this guard is accessible. To make this guard
73
+ /// inaccessible, use [`GdCell::make_inaccessible()`](crate::GdCell::make_inaccessible) on a mutable
74
+ /// reference handed out by this guard.
74
75
#[ derive( Debug ) ]
75
76
pub struct MutGuard < ' a , T > {
76
77
state : & ' a Mutex < CellState < T > > ,
@@ -101,11 +102,11 @@ impl<'a, T> MutGuard<'a, T> {
101
102
/// This is the case because:
102
103
/// - [`GdCell`](super::GdCell) will not create any new references while this guard exists and is
103
104
/// accessible.
104
- /// - When it is marked as inaccessible it is impossible to have any `&self` or `&mut self` references to
105
- /// this guard that can be used. Because we take in a `&mut self` reference with a lifetime `'a` and
106
- /// return an [`InaccessibleGuard`] with a lifetime `'b` where `'a: 'b` which ensure that the
107
- /// `&mut self` outlives that guard and cannot be used until the guard is dropped. And the rust
108
- /// borrow-checker will prevent any new references from being made.
105
+ /// - When it is made inaccessible it is impossible to have any `&self` or `&mut self` references to this
106
+ /// guard that can be used. Because we take in a `&mut self` reference with a lifetime `'a` and return
107
+ /// an [`InaccessibleGuard`] with a lifetime `'b` where `'a: 'b` which ensure that the `&mut self`
108
+ /// outlives that guard and cannot be used until the guard is dropped. And the rust borrow-checker will
109
+ /// prevent any new references from being made.
109
110
/// - When it is made inaccessible, [`GdCell`](super::GdCell) will also ensure that any new references
110
111
/// are derived from this guard's `value` pointer, thus preventing `value` from being invalidated.
111
112
pub ( crate ) unsafe fn new (
@@ -128,13 +129,23 @@ impl<'a, T> Deref for MutGuard<'a, T> {
128
129
let count = self . state . lock ( ) . unwrap ( ) . borrow_state . mut_count ( ) ;
129
130
// This is just a best-effort error check. It should never be triggered.
130
131
assert_eq ! (
131
- self . count, count,
132
- "attempted to access the non-current mutable borrow. **this is a bug, please report it**"
132
+ self . count,
133
+ count,
134
+ "\
135
+ attempted to access a non-current mutable borrow of type: `{}`. \n \
136
+ current count: {}\n \
137
+ value pointer: {:p}\n \
138
+ attempted access count: {}\n \
139
+ **this is a bug, please report it**\
140
+ ",
141
+ std:: any:: type_name:: <T >( ) ,
142
+ self . count,
143
+ self . value,
144
+ count
133
145
) ;
134
146
135
- // SAFETY:
136
- // It is safe to call `as_ref()` on value when we have a `&self` reference because of the safety
137
- // invariants of `new`.
147
+ // SAFETY: It is safe to call `as_ref()` on value when we have a `&self` reference because of the
148
+ // safety invariants of `new`.
138
149
unsafe { self . value . as_ref ( ) }
139
150
}
140
151
}
@@ -144,8 +155,19 @@ impl<'a, T> DerefMut for MutGuard<'a, T> {
144
155
let count = self . state . lock ( ) . unwrap ( ) . borrow_state . mut_count ( ) ;
145
156
// This is just a best-effort error check. It should never be triggered.
146
157
assert_eq ! (
147
- self . count, count,
148
- "attempted to access the non-current mutable borrow. **this is a bug, please report it**"
158
+ self . count,
159
+ count,
160
+ "\
161
+ attempted to access a non-current mutable borrow of type: `{}`. \n \
162
+ current count: {}\n \
163
+ value pointer: {:p}\n \
164
+ attempted access count: {}\n \
165
+ **this is a bug, please report it**\
166
+ ",
167
+ std:: any:: type_name:: <T >( ) ,
168
+ self . count,
169
+ self . value,
170
+ count
149
171
) ;
150
172
151
173
// SAFETY:
@@ -170,22 +192,29 @@ impl<'a, T> Drop for MutGuard<'a, T> {
170
192
171
193
/// A guard that ensures a mutable reference is kept inaccessible until it is dropped.
172
194
///
173
- /// The current reference is stored in the guard and we push a new reference to `state` on creation. We then
174
- /// undo this upon dropping the guard .
195
+ /// We store the current reference in the guard upon creation, and push a new reference to `state` on
196
+ /// creation. When the guard is dropped, `state`'s pointer is reset to the original pointer .
175
197
///
176
- /// This ensure that any new references are derived from the new reference we pass in, and when this guard is
177
- /// dropped we reset it to the previous reference .
198
+ /// This ensures that any new references are derived from the new reference we pass in, and when this guard
199
+ /// is dropped the state is reset to what it was before, as if this guard never existed .
178
200
#[ derive( Debug ) ]
179
201
pub struct InaccessibleGuard < ' a , T > {
180
202
state : & ' a Mutex < CellState < T > > ,
203
+ stack_depth : usize ,
181
204
prev_ptr : NonNull < T > ,
182
205
}
183
206
184
207
impl < ' a , T > InaccessibleGuard < ' a , T > {
185
208
/// Create a new inaccessible guard for `state`.
186
209
///
187
210
/// Since `'b` must outlive `'a`, we cannot have any other references aliasing `new_ref` while this
188
- /// guard exists.
211
+ /// guard exists. So this guard ensures that the guard that handed out `new_ref` is inaccessible while
212
+ /// this guard exists.
213
+ ///
214
+ /// Will error if:
215
+ /// - There is currently no accessible mutable borrow.
216
+ /// - There are any shared references.
217
+ /// - `new_ref` is not equal to the pointer in `state`.
189
218
pub ( crate ) fn new < ' b > (
190
219
state : & ' a Mutex < CellState < T > > ,
191
220
new_ref : & ' b mut T ,
@@ -205,16 +234,53 @@ impl<'a, T> InaccessibleGuard<'a, T> {
205
234
206
235
guard. borrow_state . set_inaccessible ( ) ?;
207
236
let prev_ptr = guard. get_ptr ( ) ;
208
- guard. set_ptr ( new_ptr) ;
237
+ let stack_depth = guard. push_ptr ( new_ptr) ;
238
+
239
+ Ok ( Self {
240
+ state,
241
+ stack_depth,
242
+ prev_ptr,
243
+ } )
244
+ }
209
245
210
- Ok ( Self { state, prev_ptr } )
246
+ /// Single implementation of drop-logic for use in both drop implementations.
247
+ fn perform_drop (
248
+ mut state : MutexGuard < ' _ , CellState < T > > ,
249
+ prev_ptr : NonNull < T > ,
250
+ stack_depth : usize ,
251
+ ) {
252
+ if state. stack_depth != stack_depth {
253
+ state
254
+ . borrow_state
255
+ . poison ( "cannot drop inaccessible guards in the wrong order" )
256
+ . unwrap ( ) ;
257
+ }
258
+ state. borrow_state . unset_inaccessible ( ) . unwrap ( ) ;
259
+ state. pop_ptr ( prev_ptr) ;
260
+ }
261
+
262
+ /// Drop self if possible, otherwise returns self again.
263
+ ///
264
+ /// Used currently in the mock-tests, as we need a thread safe way to drop self. Using the normal drop
265
+ /// logic may poison state, however it should not cause any UB either way.
266
+ #[ doc( hidden) ]
267
+ pub fn try_drop ( self ) -> Result < ( ) , std:: mem:: ManuallyDrop < Self > > {
268
+ let manual = std:: mem:: ManuallyDrop :: new ( self ) ;
269
+ let state = manual. state . lock ( ) . unwrap ( ) ;
270
+ if !state. borrow_state . may_unset_inaccessible ( ) || state. stack_depth != manual. stack_depth {
271
+ return Err ( manual) ;
272
+ }
273
+ Self :: perform_drop ( state, manual. prev_ptr , manual. stack_depth ) ;
274
+
275
+ Ok ( ( ) )
211
276
}
212
277
}
213
278
214
279
impl < ' a , T > Drop for InaccessibleGuard < ' a , T > {
215
280
fn drop ( & mut self ) {
216
- let mut state = self . state . lock ( ) . unwrap ( ) ;
217
- state. borrow_state . unset_inaccessible ( ) . unwrap ( ) ;
218
- state. set_ptr ( self . prev_ptr ) ;
281
+ // Default behavior of drop-logic simply panics and poisons the cell on failure. This is appropriate
282
+ // for single-threaded code where no errors should happen here.
283
+ let state = self . state . lock ( ) . unwrap ( ) ;
284
+ Self :: perform_drop ( state, self . prev_ptr , self . stack_depth ) ;
219
285
}
220
286
}
0 commit comments