@@ -186,7 +186,7 @@ macro_rules! new {
186
186
Self {
187
187
hazptrs: HazPtrRecords {
188
188
head: AtomicPtr :: new( core:: ptr:: null_mut( ) ) ,
189
- head_available: AtomicUsize :: new( 0 ) ,
189
+ head_available: AtomicPtr :: new( core :: ptr :: null_mut ( ) ) ,
190
190
count: AtomicIsize :: new( 0 ) ,
191
191
} ,
192
192
untagged,
@@ -257,24 +257,28 @@ impl<F> Domain<F> {
257
257
258
258
loop {
259
259
let avail = self . hazptrs . head_available . load ( Ordering :: Acquire ) ;
260
- if avail == core :: ptr :: null :: < HazPtrRecord > ( ) as usize {
261
- return ( core :: ptr :: null_mut ( ) , 0 ) ;
260
+ if avail. is_null ( ) {
261
+ return ( avail , 0 ) ;
262
262
}
263
- debug_assert_ne ! ( avail, core :: ptr :: null :: < HazPtrRecord > ( ) as usize | LOCK_BIT ) ;
263
+ debug_assert_ne ! ( avail, LOCK_BIT as * mut _ ) ;
264
264
if ( avail as usize & LOCK_BIT ) == 0 {
265
- // Definitely a valid pointer now.
266
- let avail: * const HazPtrRecord = avail as _ ;
267
-
268
265
// The available list is not currently locked.
269
266
//
270
267
// XXX: This could be a fetch_or and allow progress even if there's a new (but
271
- // unlocked) head.
268
+ // unlocked) head. However, `AtomicPtr` doesn't support fetch_or at the moment, so
269
+ // we'd have to convert it to an `AtomicUsize`. This will in turn make Miri fail
270
+ // (with -Zmiri-tag-raw-pointers, which we want enabled) to track the provenance of
271
+ // the pointer in question through the int-to-ptr conversion. The workaround is
272
+ // probably to mock a type that is `AtomicUsize` with `fetch_or` with
273
+ // `#[cfg(not(miri))]`, but is `AtomicPtr` with `compare_exchange` with
274
+ // `#[cfg(miri)]`. It ain't pretty, but should do the job. The issue is tracked in
275
+ // https://github.com/rust-lang/miri/issues/1993.
272
276
if self
273
277
. hazptrs
274
278
. head_available
275
279
. compare_exchange_weak (
276
- avail as usize ,
277
- avail as usize | LOCK_BIT ,
280
+ avail,
281
+ with_lock_bit ( avail) ,
278
282
Ordering :: AcqRel ,
279
283
Ordering :: Relaxed ,
280
284
)
@@ -317,9 +321,7 @@ impl<F> Domain<F> {
317
321
}
318
322
319
323
// NOTE: This releases the lock
320
- self . hazptrs
321
- . head_available
322
- . store ( next as usize , Ordering :: Release ) ;
324
+ self . hazptrs . head_available . store ( next, Ordering :: Release ) ;
323
325
unsafe { & * tail }
324
326
. available_next
325
327
. store ( core:: ptr:: null_mut ( ) , Ordering :: Relaxed ) ;
@@ -335,15 +337,15 @@ impl<F> Domain<F> {
335
337
debug_assert_eq ! ( head as * const _ as usize & LOCK_BIT , 0 ) ;
336
338
loop {
337
339
let avail = self . hazptrs . head_available . load ( Ordering :: Acquire ) ;
338
- if ( avail & LOCK_BIT ) == 0 {
340
+ if ( avail as usize & LOCK_BIT ) == 0 {
339
341
tail. available_next
340
342
. store ( avail as * mut _ , Ordering :: Relaxed ) ;
341
343
if self
342
344
. hazptrs
343
345
. head_available
344
346
. compare_exchange_weak (
345
347
avail,
346
- head as * const _ as usize ,
348
+ head as * const _ as * mut _ ,
347
349
Ordering :: AcqRel ,
348
350
Ordering :: Relaxed ,
349
351
)
@@ -724,7 +726,7 @@ impl<F> Drop for Domain<F> {
724
726
725
727
struct HazPtrRecords {
726
728
head : AtomicPtr < HazPtrRecord > ,
727
- head_available : AtomicUsize , // really *mut HazPtrRecord
729
+ head_available : AtomicPtr < HazPtrRecord > ,
728
730
count : AtomicIsize ,
729
731
}
730
732
@@ -815,6 +817,19 @@ impl RetiredList {
815
817
}
816
818
}
817
819
820
+ // Helpers to set and unset the lock bit on a `*mut HazPtrRecord` without losing pointer
821
+ // provenance. See https://github.com/rust-lang/miri/issues/1993 for details.
822
+ fn with_lock_bit ( ptr : * mut HazPtrRecord ) -> * mut HazPtrRecord {
823
+ int_to_ptr_with_provenance ( ptr as usize | LOCK_BIT , ptr)
824
+ }
825
+ fn without_lock_bit ( ptr : * mut HazPtrRecord ) -> * mut HazPtrRecord {
826
+ int_to_ptr_with_provenance ( ptr as usize & !LOCK_BIT , ptr)
827
+ }
828
+ fn int_to_ptr_with_provenance < T > ( addr : usize , prov : * mut T ) -> * mut T {
829
+ let ptr = prov. cast :: < u8 > ( ) ;
830
+ ptr. wrapping_add ( addr. wrapping_sub ( ptr as usize ) ) . cast ( )
831
+ }
832
+
818
833
/*
819
834
fn foo() {
820
835
let domain = Domain::new();
0 commit comments