@@ -34,6 +34,9 @@ use core::{
3434} ;
3535use macros:: pin_data;
3636
37+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
38+ use crate :: sync:: lockdep:: LockdepMap ;
39+
3740mod std_vendor;
3841
3942/// A reference-counted pointer to an instance of `T`.
@@ -127,6 +130,17 @@ pub struct Arc<T: ?Sized> {
127130 _p : PhantomData < ArcInner < T > > ,
128131}
129132
133+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
134+ #[ pin_data]
135+ #[ repr( C ) ]
136+ struct ArcInner < T : ?Sized > {
137+ refcount : Opaque < bindings:: refcount_t > ,
138+ lockdep_map : LockdepMap ,
139+ data : T ,
140+ }
141+
142+ // FIXME: pin_data does not work well with cfg attributes within the struct definition.
143+ #[ cfg( not( CONFIG_RUST_EXTRA_LOCKDEP ) ) ]
130144#[ pin_data]
131145#[ repr( C ) ]
132146struct ArcInner < T : ?Sized > {
@@ -157,11 +171,14 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
157171
158172impl < T > Arc < T > {
159173 /// Constructs a new reference counted instance of `T`.
174+ #[ track_caller]
160175 pub fn try_new ( contents : T ) -> Result < Self , AllocError > {
161176 // INVARIANT: The refcount is initialised to a non-zero value.
162177 let value = ArcInner {
163178 // SAFETY: There are no safety requirements for this FFI call.
164179 refcount : Opaque :: new ( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
180+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
181+ lockdep_map : LockdepMap :: new ( ) ,
165182 data : contents,
166183 } ;
167184
@@ -176,6 +193,7 @@ impl<T> Arc<T> {
176193 ///
177194 /// If `T: !Unpin` it will not be able to move afterwards.
178195 #[ inline]
196+ #[ track_caller]
179197 pub fn pin_init < E > ( init : impl PinInit < T , E > ) -> error:: Result < Self >
180198 where
181199 Error : From < E > ,
@@ -187,6 +205,7 @@ impl<T> Arc<T> {
187205 ///
188206 /// This is equivalent to [`pin_init`], since an [`Arc`] is always pinned.
189207 #[ inline]
208+ #[ track_caller]
190209 pub fn init < E > ( init : impl Init < T , E > ) -> error:: Result < Self >
191210 where
192211 Error : From < E > ,
@@ -279,15 +298,46 @@ impl<T: ?Sized> Drop for Arc<T> {
279298 // freed/invalid memory as long as it is never dereferenced.
280299 let refcount = unsafe { self . ptr . as_ref ( ) } . refcount . get ( ) ;
281300
301+ // SAFETY: By the type invariant, there is necessarily a reference to the object.
302+ // We cannot hold the map lock across the reference decrement, as we might race
303+ // another thread. Therefore, we lock and immediately drop the guard here. This
304+ // only serves to inform lockdep of the dependency up the call stack.
305+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
306+ unsafe { self . ptr . as_ref ( ) } . lockdep_map . lock ( ) ;
307+
282308 // INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and
283309 // this instance is being dropped, so the broken invariant is not observable.
284310 // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
285311 let is_zero = unsafe { bindings:: refcount_dec_and_test ( refcount) } ;
312+
286313 if is_zero {
287314 // The count reached zero, we must free the memory.
288- //
289- // SAFETY: The pointer was initialised from the result of `Box::leak`.
290- unsafe { Box :: from_raw ( self . ptr . as_ptr ( ) ) } ;
315+
316+ // SAFETY: If we get this far, we had the last reference to the object.
317+ // That means we are responsible for freeing it, so we can safely lock
318+ // the fake lock again. This wraps dropping the inner object, which
319+ // informs lockdep of the dependencies down the call stack.
320+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
321+ let guard = unsafe { self . ptr . as_ref ( ) } . lockdep_map . lock ( ) ;
322+
323+ // SAFETY: The pointer was initialised from the result of `Box::leak`,
324+ // and the value is valid.
325+ unsafe { core:: ptr:: drop_in_place ( & mut self . ptr . as_mut ( ) . data ) } ;
326+
327+ // We need to drop the lock guard before freeing the LockdepMap itself
328+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
329+ core:: mem:: drop ( guard) ;
330+
331+ // SAFETY: The pointer was initialised from the result of `Box::leak`,
332+ // and the lockdep map is valid.
333+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
334+ unsafe {
335+ core:: ptr:: drop_in_place ( & mut self . ptr . as_mut ( ) . lockdep_map )
336+ } ;
337+
338+ // SAFETY: The pointer was initialised from the result of `Box::leak`, and
339+ // a ManuallyDrop<T> is compatible. We already dropped the contents above.
340+ unsafe { Box :: from_raw ( self . ptr . as_ptr ( ) as * mut ManuallyDrop < ArcInner < T > > ) } ;
291341 }
292342 }
293343}
@@ -499,6 +549,7 @@ pub struct UniqueArc<T: ?Sized> {
499549
500550impl < T > UniqueArc < T > {
501551 /// Tries to allocate a new [`UniqueArc`] instance.
552+ #[ track_caller]
502553 pub fn try_new ( value : T ) -> Result < Self , AllocError > {
503554 Ok ( Self {
504555 // INVARIANT: The newly-created object has a ref-count of 1.
@@ -507,13 +558,27 @@ impl<T> UniqueArc<T> {
507558 }
508559
509560 /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet.
561+ #[ track_caller]
510562 pub fn try_new_uninit ( ) -> Result < UniqueArc < MaybeUninit < T > > , AllocError > {
511563 // INVARIANT: The refcount is initialised to a non-zero value.
564+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
565+ let inner = {
566+ let map = LockdepMap :: new ( ) ;
567+ Box :: try_init :: < AllocError > ( try_init ! ( ArcInner {
568+ // SAFETY: There are no safety requirements for this FFI call.
569+ refcount: Opaque :: new( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
570+ lockdep_map: map,
571+ data <- init:: uninit:: <T , AllocError >( ) ,
572+ } ? AllocError ) ) ?
573+ } ;
574+ // FIXME: try_init!() does not work with cfg attributes.
575+ #[ cfg( not( CONFIG_RUST_EXTRA_LOCKDEP ) ) ]
512576 let inner = Box :: try_init :: < AllocError > ( try_init ! ( ArcInner {
513577 // SAFETY: There are no safety requirements for this FFI call.
514578 refcount: Opaque :: new( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
515579 data <- init:: uninit:: <T , AllocError >( ) ,
516580 } ? AllocError ) ) ?;
581+
517582 Ok ( UniqueArc {
518583 // INVARIANT: The newly-created object has a ref-count of 1.
519584 // SAFETY: The pointer from the `Box` is valid.
0 commit comments