@@ -291,6 +291,68 @@ impl<T: ?Sized> Arc<T> {
291
291
pub fn ptr_eq ( this : & Self , other : & Self ) -> bool {
292
292
core:: ptr:: eq ( this. ptr . as_ptr ( ) , other. ptr . as_ptr ( ) )
293
293
}
294
+
295
+ /// Converts this [`Arc`] into a [`UniqueArc`], or destroys it if it is not unique.
296
+ ///
297
+ /// When this destroys the `Arc`, it does so while properly avoiding races. This means that
298
+ /// this method will never call the destructor of the value.
299
+ ///
300
+ /// # Examples
301
+ ///
302
+ /// ```
303
+ /// use kernel::sync::{Arc, UniqueArc};
304
+ ///
305
+ /// let arc = Arc::try_new(42)?;
306
+ /// let unique_arc = arc.into_unique_or_drop();
307
+ ///
308
+ /// // The above conversion should succeed since refcount of `arc` is 1.
309
+ /// assert!(unique_arc.is_some());
310
+ ///
311
+ /// assert_eq!(*(unique_arc.unwrap()), 42);
312
+ ///
313
+ /// # Ok::<(), Error>(())
314
+ /// ```
315
+ ///
316
+ /// ```
317
+ /// use kernel::sync::{Arc, UniqueArc};
318
+ ///
319
+ /// let arc = Arc::try_new(42)?;
320
+ /// let another = arc.clone();
321
+ ///
322
+ /// let unique_arc = arc.into_unique_or_drop();
323
+ ///
324
+ /// // The above conversion should fail since refcount of `arc` is >1.
325
+ /// assert!(unique_arc.is_none());
326
+ ///
327
+ /// # Ok::<(), Error>(())
328
+ /// ```
329
+ pub fn into_unique_or_drop ( self ) -> Option < Pin < UniqueArc < T > > > {
330
+ // We will manually manage the refcount in this method, so we disable the destructor.
331
+ let me = ManuallyDrop :: new ( self ) ;
332
+ // SAFETY: We own a refcount, so the pointer is still valid.
333
+ let refcount = unsafe { me. ptr . as_ref ( ) } . refcount . get ( ) ;
334
+
335
+ // If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will
336
+ // return without further touching the `Arc`. If the refcount reaches zero, then there are
337
+ // no other arcs, and we can create a `UniqueArc`.
338
+ //
339
+ // SAFETY: We own a refcount, so the pointer is not dangling.
340
+ let is_zero = unsafe { bindings:: refcount_dec_and_test ( refcount) } ;
341
+ if is_zero {
342
+ // SAFETY: We have exclusive access to the arc, so we can perform unsynchronized
343
+ // accesses to the refcount.
344
+ unsafe { core:: ptr:: write ( refcount, bindings:: REFCOUNT_INIT ( 1 ) ) } ;
345
+
346
+ // INVARIANT: We own the only refcount to this arc, so we may create a `UniqueArc`. We
347
+ // must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin
348
+ // their values.
349
+ Some ( Pin :: from ( UniqueArc {
350
+ inner : ManuallyDrop :: into_inner ( me) ,
351
+ } ) )
352
+ } else {
353
+ None
354
+ }
355
+ }
294
356
}
295
357
296
358
impl < T : ' static > ForeignOwnable for Arc < T > {
0 commit comments