@@ -37,10 +37,15 @@ pub(super) trait Latch {
37
37
///
38
38
/// Setting a latch triggers other threads to wake up and (in some
39
39
/// cases) complete. This may, in turn, cause memory to be
40
- /// allocated and so forth. One must be very careful about this,
40
+ /// deallocated and so forth. One must be very careful about this,
41
41
/// and it's typically better to read all the fields you will need
42
42
/// to access *before* a latch is set!
43
- fn set ( & self ) ;
43
+ ///
44
+ /// This function operates on `*const Self` instead of `&self` to allow it
45
+ /// to become dangling during this call. The caller must ensure that the
46
+ /// pointer is valid upon entry, and not invalidated during the call by any
47
+ /// actions other than `set` itself.
48
+ unsafe fn set ( this : * const Self ) ;
44
49
}
45
50
46
51
pub ( super ) trait AsCoreLatch {
@@ -123,8 +128,8 @@ impl CoreLatch {
123
128
/// doing some wakeups; those are encapsulated in the surrounding
124
129
/// latch code.
125
130
#[ inline]
126
- fn set ( & self ) -> bool {
127
- let old_state = self . state . swap ( SET , Ordering :: AcqRel ) ;
131
+ unsafe fn set ( this : * const Self ) -> bool {
132
+ let old_state = ( * this ) . state . swap ( SET , Ordering :: AcqRel ) ;
128
133
old_state == SLEEPING
129
134
}
130
135
@@ -186,29 +191,29 @@ impl<'r> AsCoreLatch for SpinLatch<'r> {
186
191
187
192
impl < ' r > Latch for SpinLatch < ' r > {
188
193
#[ inline]
189
- fn set ( & self ) {
194
+ unsafe fn set ( this : * const Self ) {
190
195
let cross_registry;
191
196
192
- let registry: & Registry = if self . cross {
197
+ let registry: & Registry = if ( * this ) . cross {
193
198
// Ensure the registry stays alive while we notify it.
194
199
// Otherwise, it would be possible that we set the spin
195
200
// latch and the other thread sees it and exits, causing
196
201
// the registry to be deallocated, all before we get a
197
202
// chance to invoke `registry.notify_worker_latch_is_set`.
198
- cross_registry = Arc :: clone ( self . registry ) ;
203
+ cross_registry = Arc :: clone ( ( * this ) . registry ) ;
199
204
& cross_registry
200
205
} else {
201
206
// If this is not a "cross-registry" spin-latch, then the
202
207
// thread which is performing `set` is itself ensuring
203
208
// that the registry stays alive. However, that doesn't
204
209
// include this *particular* `Arc` handle if the waiting
205
210
// thread then exits, so we must completely dereference it.
206
- self . registry
211
+ ( * this ) . registry
207
212
} ;
208
- let target_worker_index = self . target_worker_index ;
213
+ let target_worker_index = ( * this ) . target_worker_index ;
209
214
210
- // NOTE: Once we `set`, the target may proceed and invalidate `&self `!
211
- if self . core_latch . set ( ) {
215
+ // NOTE: Once we `set`, the target may proceed and invalidate `this `!
216
+ if CoreLatch :: set ( & ( * this ) . core_latch ) {
212
217
// Subtle: at this point, we can no longer read from
213
218
// `self`, because the thread owning this spin latch may
214
219
// have awoken and deallocated the latch. Therefore, we
@@ -255,10 +260,10 @@ impl LockLatch {
255
260
256
261
impl Latch for LockLatch {
257
262
#[ inline]
258
- fn set ( & self ) {
259
- let mut guard = self . m . lock ( ) . unwrap ( ) ;
263
+ unsafe fn set ( this : * const Self ) {
264
+ let mut guard = ( * this ) . m . lock ( ) . unwrap ( ) ;
260
265
* guard = true ;
261
- self . v . notify_all ( ) ;
266
+ ( * this ) . v . notify_all ( ) ;
262
267
}
263
268
}
264
269
@@ -307,9 +312,9 @@ impl CountLatch {
307
312
/// count, then the latch is **set**, and calls to `probe()` will
308
313
/// return true. Returns whether the latch was set.
309
314
#[ inline]
310
- pub ( super ) fn set ( & self ) -> bool {
311
- if self . counter . fetch_sub ( 1 , Ordering :: SeqCst ) == 1 {
312
- self . core_latch . set ( ) ;
315
+ pub ( super ) unsafe fn set ( this : * const Self ) -> bool {
316
+ if ( * this ) . counter . fetch_sub ( 1 , Ordering :: SeqCst ) == 1 {
317
+ CoreLatch :: set ( & ( * this ) . core_latch ) ;
313
318
true
314
319
} else {
315
320
false
@@ -320,8 +325,12 @@ impl CountLatch {
320
325
/// the latch is set, then the specific worker thread is tickled,
321
326
/// which should be the one that owns this latch.
322
327
#[ inline]
323
- pub ( super ) fn set_and_tickle_one ( & self , registry : & Registry , target_worker_index : usize ) {
324
- if self . set ( ) {
328
+ pub ( super ) unsafe fn set_and_tickle_one (
329
+ this : * const Self ,
330
+ registry : & Registry ,
331
+ target_worker_index : usize ,
332
+ ) {
333
+ if Self :: set ( this) {
325
334
registry. notify_worker_latch_is_set ( target_worker_index) ;
326
335
}
327
336
}
@@ -362,9 +371,9 @@ impl CountLockLatch {
362
371
363
372
impl Latch for CountLockLatch {
364
373
#[ inline]
365
- fn set ( & self ) {
366
- if self . counter . fetch_sub ( 1 , Ordering :: SeqCst ) == 1 {
367
- self . lock_latch . set ( ) ;
374
+ unsafe fn set ( this : * const Self ) {
375
+ if ( * this ) . counter . fetch_sub ( 1 , Ordering :: SeqCst ) == 1 {
376
+ LockLatch :: set ( & ( * this ) . lock_latch ) ;
368
377
}
369
378
}
370
379
}
@@ -374,7 +383,7 @@ where
374
383
L : Latch ,
375
384
{
376
385
#[ inline]
377
- fn set ( & self ) {
378
- L :: set ( self ) ;
386
+ unsafe fn set ( this : * const Self ) {
387
+ L :: set ( & * * this ) ;
379
388
}
380
389
}
0 commit comments