Skip to main content

starnix_types/
ownership.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! This crates introduces a framework to handle explicit ownership.
6//!
7//! Explicit ownership is used for object that needs to be cleaned, but cannot use `Drop` because
8//! the release operation requires a context. For example, when using the rust types to ensures the
9//! locking order, taking a lock requires knowing what locks are already held at this point, and
10//! uses an explicit object to represent this. If the object needs to take a lock during the
11//! release operation, `Drop` cannot provide it.
12//!
13//! An object that uses explicit ownership uses the `Releasable` trait. The user must calls the
14//! `release` method on it before it goes out of scope.
15//!
16//! A shared object that used explicit ownership used the `OwnedRef`/`WeakRef`/`TempRef`
17//! containers.
18//! The meaning are the following:
19//! - Object that owns the shared object use `OwnedRef`. They are responsible to call `release`
20//! before dropping the reference.
21//! - Object that do not owned the shared object use `WeakRef`. This acts as a weak reference to
22//! the object. They can convert it to a strong reference using the `upgrade` method. The returned
23//! value is an `Option<TempRef>`. The `TempRef` allows access to the object. Because this doesn't
24//! repsent ownership, the `TempRef` must not be kept, in particular, the user should not do any
25//! blocking operation while having a `TempRef`.
26
27// Not all instance of OwnedRef and Releasable are used in non test code yet.
28#![allow(dead_code)]
29
30// TODO(https://fxbug.dev/42081310): Create a linter to ensure TempRef is not held while calling any blocking
31// operation.
32
33use core::hash::Hasher;
34
35use std::hash::Hash;
36use std::ops::Deref;
37use std::sync::atomic::{AtomicUsize, Ordering, fence};
38use std::sync::{Arc, Weak};
39
40/// The base trait for explicit ownership. Any `Releasable` object must call `release` before
41/// being dropped.
42pub trait Releasable {
43    type Context<'a>;
44
45    // TODO(https://fxbug.dev/42081308): Only the `self` version should exist, but this is
46    // problematic with Task and CurrentTask at this point.
47    fn release<'a>(self: Self, c: Self::Context<'a>);
48}
49
50/// Releasing an option calls release if the option is not empty.
51impl<T: Releasable> Releasable for Option<T> {
52    type Context<'a> = T::Context<'a>;
53
54    fn release<'a>(self: Self, c: Self::Context<'a>) {
55        if let Some(v) = self {
56            v.release(c);
57        }
58    }
59}
60
61/// Releasing a vec calls release on each element
62impl<T: Releasable> Releasable for Vec<T>
63where
64    for<'a> T::Context<'a>: Clone,
65{
66    type Context<'a> = T::Context<'a>;
67
68    fn release<'a>(self: Self, c: Self::Context<'a>) {
69        for v in self {
70            v.release(c.clone());
71        }
72    }
73}
74
75/// Releasing a result calls release on the value if the result is ok.
76impl<T: Releasable, E> Releasable for Result<T, E> {
77    type Context<'a> = T::Context<'a>;
78
79    fn release<'a>(self: Self, c: Self::Context<'a>) {
80        if let Ok(v) = self {
81            v.release(c);
82        }
83    }
84}
85
86impl<T: Releasable> Releasable for ReleaseGuard<T> {
87    type Context<'a> = T::Context<'a>;
88
89    fn release<'a>(self: Self, c: Self::Context<'a>) {
90        self.drop_guard.disarm();
91        self.value.release(c);
92    }
93}
94
95/// Trait for object that can be shared. This is an equivalent of `Clone` for objects that require
96/// to be released.
97pub trait Share {
98    fn share(&self) -> Self;
99}
100
101impl<T: Share> Share for Option<T> {
102    fn share(&self) -> Self {
103        match self {
104            None => None,
105            Some(t) => Some(t.share()),
106        }
107    }
108}
109
110/// An owning reference to a shared owned object. Each instance must call `release` before being
111/// dropped.
112/// `OwnedRef` will panic on Drop in debug builds if it has not been released.
113#[must_use = "OwnedRef must be released"]
114pub struct OwnedRef<T> {
115    /// The shared data.
116    inner: Option<Arc<RefInner<T>>>,
117
118    /// A guard that will ensure a panic on drop if the ref has not been released.
119    drop_guard: DropGuard,
120}
121
122impl<T> OwnedRef<T> {
123    pub fn new(value: T) -> Self {
124        Self { inner: Some(Arc::new(RefInner::new(value))), drop_guard: Default::default() }
125    }
126
127    pub fn new_cyclic<F>(data_fn: F) -> Self
128    where
129        F: FnOnce(WeakRef<T>) -> T,
130    {
131        let inner = Arc::new_cyclic(|weak_inner| {
132            let weak = WeakRef(weak_inner.clone());
133            RefInner::new(data_fn(weak))
134        });
135        Self { inner: Some(inner), drop_guard: Default::default() }
136    }
137
138    /// Provides a raw pointer to the data.
139    ///
140    /// See `Arc::as_ptr`
141    pub fn as_ptr(this: &Self) -> *const T {
142        &Self::inner(this).value.value as *const T
143    }
144
145    /// Returns true if the two objects point to the same allocation
146    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
147        Self::as_ptr(this) == Self::as_ptr(other)
148    }
149
150    /// Produce a `WeakRef` from a `OwnedRef`.
151    pub fn downgrade(this: &Self) -> WeakRef<T> {
152        WeakRef(Arc::downgrade(Self::inner(this)))
153    }
154
155    /// Produce a `TempRef` from a `OwnedRef`. As an `OwnedRef` exists at the time of the creation,
156    /// this cannot fail.
157    pub fn temp(this: &Self) -> TempRef<'_, T> {
158        TempRef::new(Arc::clone(Self::inner(this)))
159    }
160
161    fn inner(this: &Self) -> &Arc<RefInner<T>> {
162        this.inner.as_ref().unwrap_or_else(|| {
163            panic!("OwnedRef<{}> has been released.", std::any::type_name::<T>())
164        })
165    }
166
167    fn re_own(inner: Arc<RefInner<T>>) -> Option<Self> {
168        let mut owned_refs = inner.owned_refs_count.load(Ordering::Relaxed);
169        loop {
170            if owned_refs == 0 {
171                return None;
172            }
173            match inner.owned_refs_count.compare_exchange(
174                owned_refs,
175                owned_refs + 1,
176                Ordering::Acquire,
177                Ordering::Relaxed,
178            ) {
179                Ok(_) => {
180                    return Some(Self { inner: Some(inner), drop_guard: Default::default() });
181                }
182                Err(v) => {
183                    owned_refs = v;
184                }
185            }
186        }
187    }
188}
189
190impl<T: Releasable> OwnedRef<T> {
191    /// Take the releasable from the `OwnedRef`. Returns None if the `OwnedRef` is not the last
192    /// reference to the data.
193    pub fn take(this: &mut Self) -> Option<ReleaseGuard<T>> {
194        this.drop_guard.disarm();
195        let inner = this.inner.take().unwrap_or_else(|| {
196            panic!("OwnedRef<{}> has been released.", std::any::type_name::<T>())
197        });
198        let previous_count = inner.owned_refs_count.fetch_sub(1, Ordering::Release);
199        if previous_count == 1 {
200            fence(Ordering::Acquire);
201            Some(Self::wait_and_take_value(inner))
202        } else {
203            None
204        }
205    }
206
207    /// Wait for this `OwnedRef` to be the only left reference to the data. This should only be
208    /// called on once the last `OwnedRef` has been released. This will wait for all existing
209    /// `TempRef >]` to be dropped before returning.
210    fn wait_and_take_value(mut inner: Arc<RefInner<T>>) -> ReleaseGuard<T> {
211        loop {
212            // Ensure no more `OwnedRef` exists.
213            debug_assert_eq!(inner.owned_refs_count.load(Ordering::Acquire), 0);
214            match Arc::try_unwrap(inner) {
215                Ok(value) => return value.value,
216                Err(value) => inner = value,
217            }
218            inner.wait_for_no_ref_once();
219        }
220    }
221}
222
223impl<T: std::fmt::Debug> std::fmt::Debug for OwnedRef<T> {
224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225        Self::inner(self).value.fmt(f)
226    }
227}
228
229impl<T: Releasable> Share for OwnedRef<T> {
230    /// Clone the `OwnedRef`. Both the current and the new reference needs to be `release`d.
231    fn share(&self) -> Self {
232        let inner = Self::inner(self);
233        let previous_count = inner.owned_refs_count.fetch_add(1, Ordering::Relaxed);
234        debug_assert!(previous_count > 0, "OwnedRef should not be used after being released.");
235        Self { inner: Some(Arc::clone(inner)), drop_guard: Default::default() }
236    }
237}
238
239impl<T: Releasable> Releasable for OwnedRef<T> {
240    type Context<'a> = T::Context<'a>;
241
242    /// Release the `OwnedRef`. If this is the last instance, this method will block until all
243    /// `TempRef` instances are dropped, and will release the underlying object.
244    #[allow(unused_mut)]
245    fn release<'a>(mut self, c: Self::Context<'a>) {
246        OwnedRef::take(&mut self).release(c);
247    }
248}
249
250impl<T: Default> Default for OwnedRef<T> {
251    fn default() -> Self {
252        Self::new(T::default())
253    }
254}
255
256impl<T> std::ops::Deref for OwnedRef<T> {
257    type Target = T;
258
259    fn deref(&self) -> &Self::Target {
260        &Self::inner(self).deref().value
261    }
262}
263
264impl<T> std::borrow::Borrow<T> for OwnedRef<T> {
265    fn borrow(&self) -> &T {
266        self.deref()
267    }
268}
269
270impl<T> std::convert::AsRef<T> for OwnedRef<T> {
271    fn as_ref(&self) -> &T {
272        self.deref()
273    }
274}
275
276impl<T: PartialEq> PartialEq<TempRef<'_, T>> for OwnedRef<T> {
277    fn eq(&self, other: &TempRef<'_, T>) -> bool {
278        Arc::ptr_eq(Self::inner(self), &other.0)
279    }
280}
281
282impl<T: PartialEq> PartialEq for OwnedRef<T> {
283    fn eq(&self, other: &OwnedRef<T>) -> bool {
284        Arc::ptr_eq(Self::inner(self), Self::inner(other)) || **self == **other
285    }
286}
287
288impl<T: Eq> Eq for OwnedRef<T> {}
289
290impl<T: PartialOrd> PartialOrd for OwnedRef<T> {
291    fn partial_cmp(&self, other: &OwnedRef<T>) -> Option<std::cmp::Ordering> {
292        (**self).partial_cmp(&**other)
293    }
294}
295
296impl<T: Ord> Ord for OwnedRef<T> {
297    fn cmp(&self, other: &OwnedRef<T>) -> std::cmp::Ordering {
298        (**self).cmp(&**other)
299    }
300}
301
302impl<T: Hash> Hash for OwnedRef<T> {
303    fn hash<H: Hasher>(&self, state: &mut H) {
304        (**self).hash(state)
305    }
306}
307
308impl<T> From<&OwnedRef<T>> for WeakRef<T> {
309    fn from(owner: &OwnedRef<T>) -> Self {
310        OwnedRef::downgrade(owner)
311    }
312}
313
314impl<'a, T> From<&'a OwnedRef<T>> for TempRef<'a, T> {
315    fn from(owner: &'a OwnedRef<T>) -> Self {
316        OwnedRef::temp(owner)
317    }
318}
319
320impl<'a, T> From<&'a mut OwnedRef<T>> for TempRef<'a, T> {
321    fn from(owner: &'a mut OwnedRef<T>) -> Self {
322        OwnedRef::temp(owner)
323    }
324}
325
326/// A weak reference to a shared owned object. The `upgrade` method try to build a `TempRef` from a
327/// `WeakRef` and will fail if there is no `OwnedRef` left.
328#[derive(Debug)]
329pub struct WeakRef<T>(Weak<RefInner<T>>);
330
331impl<T> WeakRef<T> {
332    pub fn new() -> Self {
333        Self(Weak::new())
334    }
335
336    /// Try to upgrade the `WeakRef` into a `TempRef`. This will fail as soon as the last
337    /// `OwnedRef` is released, even if some `TempRef` still exist at that time. The returned
338    /// `TempRef` must be dropped as soon as possible. In particular, it must not be kept across
339    /// blocking calls.
340    pub fn upgrade(&self) -> Option<TempRef<'_, T>> {
341        if let Some(value) = self.0.upgrade() {
342            // As soon as the Arc has been upgraded, creates a `TempRef` to ensure the futex is woken
343            // up in case `upgrade` and `release` are racing.
344            let temp_ref = TempRef::new(value);
345            // Only returns a valid `TempRef` if there are still some un-released `OwnedRef`. As
346            // soon as `release` is called, no more `TempRef` can be acquire.
347            if temp_ref.0.owned_refs_count.load(Ordering::Acquire) > 0 {
348                return Some(temp_ref);
349            }
350        }
351        None
352    }
353
354    /// Try to upgrade the `WeakRef` into a `OwnedRef`. This will fail as soon as the last
355    /// `OwnedRef` is released.
356    pub fn re_own(&self) -> Option<OwnedRef<T>> {
357        self.0.upgrade().and_then(OwnedRef::re_own)
358    }
359
360    /// Returns a raw pointer to the object T pointed to by this WeakRef<T>, or null if this is an
361    /// empty reference.
362    ///
363    /// See `Weak::as_ptr`
364    pub fn as_ptr(&self) -> *const T {
365        if Weak::ptr_eq(&self.0, &Weak::new()) {
366            return std::ptr::null();
367        }
368        let base = self.0.as_ptr();
369        let value = memoffset::raw_field!(base, RefInner<T>, value);
370        memoffset::raw_field!(value, ReleaseGuard<T>, value)
371    }
372
373    /// Returns true if the two objects point to the same allocation
374    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
375        Weak::ptr_eq(&this.0, &other.0)
376    }
377}
378
379impl<T> Default for WeakRef<T> {
380    fn default() -> Self {
381        Self::new()
382    }
383}
384
385impl<T> Clone for WeakRef<T> {
386    fn clone(&self) -> Self {
387        Self(self.0.clone())
388    }
389}
390
391impl<T> PartialEq for WeakRef<T> {
392    fn eq(&self, other: &Self) -> bool {
393        WeakRef::ptr_eq(self, other)
394    }
395}
396
397/// Wrapper around `WeakRef` allowing to use it in a Set or as a key of a Map.
398pub struct WeakRefKey<T>(pub WeakRef<T>);
399impl<T> PartialEq for WeakRefKey<T> {
400    fn eq(&self, other: &Self) -> bool {
401        WeakRef::ptr_eq(&self.0, &other.0)
402    }
403}
404impl<T> PartialOrd for WeakRefKey<T> {
405    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
406        Some(self.cmp(other))
407    }
408}
409impl<T> Ord for WeakRefKey<T> {
410    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
411        WeakRef::as_ptr(&self.0).cmp(&WeakRef::as_ptr(&other.0))
412    }
413}
414impl<T> From<WeakRef<T>> for WeakRefKey<T> {
415    fn from(weak_ref: WeakRef<T>) -> Self {
416        Self(weak_ref)
417    }
418}
419impl<'a, T> From<&TempRef<'a, T>> for WeakRefKey<T> {
420    fn from(temp_ref: &TempRef<'a, T>) -> Self {
421        Self(WeakRef::from(temp_ref))
422    }
423}
424impl<'a, T> From<&OwnedRef<T>> for WeakRefKey<T> {
425    fn from(owned_ref: &OwnedRef<T>) -> Self {
426        Self(WeakRef::from(owned_ref))
427    }
428}
429impl<T> Clone for WeakRefKey<T> {
430    fn clone(&self) -> Self {
431        Self(self.0.clone())
432    }
433}
434impl<T> Eq for WeakRefKey<T> {}
435impl<T> Hash for WeakRefKey<T> {
436    fn hash<H: Hasher>(&self, state: &mut H) {
437        WeakRef::as_ptr(&self.0).hash(state);
438    }
439}
440impl<T> std::ops::Deref for WeakRefKey<T> {
441    type Target = WeakRef<T>;
442    fn deref(&self) -> &Self::Target {
443        &self.0
444    }
445}
446impl<T> std::fmt::Debug for WeakRefKey<T> {
447    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
448        fmt.debug_tuple(std::any::type_name::<Self>()).field(&self.0.as_ptr()).finish()
449    }
450}
451
452/// A temporary reference to a shared owned object. This permits access to the shared object, but
453/// will block any thread trying to release the last `OwnedRef`. As such, such reference must be
454/// released as soon as possible. In particular, one must not do any blocking operation while
455/// owning such a refeence.
456// Until negative trait bound are implemented, using `*mut u8` to prevent transferring TempRef
457// across threads.
458pub struct TempRef<'a, T>(Arc<RefInner<T>>, std::marker::PhantomData<(&'a T, *mut u8)>);
459
460impl<'a, T> std::fmt::Debug for TempRef<'a, T>
461where
462    T: std::fmt::Debug,
463{
464    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465        self.deref().fmt(f)
466    }
467}
468
469impl<'a, T> Drop for TempRef<'a, T> {
470    fn drop(&mut self) {
471        self.0.dec_temp_ref();
472    }
473}
474
475impl<'a, T> TempRef<'a, T> {
476    /// Build a new TempRef. Ensures `temp_refs_count` is correctly updated.
477    fn new(inner: Arc<RefInner<T>>) -> Self {
478        inner.inc_temp_ref();
479        Self(inner, Default::default())
480    }
481
482    /// Provides a raw pointer to the data.
483    ///
484    /// See `Arc::as_ptr`
485    pub fn as_ptr(this: &Self) -> *const T {
486        &this.0.value.value as *const T
487    }
488
489    /// Returns true if the two objects point to the same allocation
490    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
491        Self::as_ptr(this) == Self::as_ptr(other)
492    }
493
494    /// This allows to change the lifetime annotation of a `TempRef` to static.
495    ///
496    /// As `TempRef` must be dropped as soon as possible, this provided the way to block the release
497    /// of the related `OwnedRef`s and as such is considered sensitive. Any caller must ensure that
498    /// the returned `TempRef` is not kept around while doing blocking calls.
499    pub fn into_static(this: Self) -> TempRef<'static, T> {
500        TempRef::new(this.0.clone())
501    }
502
503    /// Try to upgrade the `WeakRef` into a `OwnedRef`. This will fail as soon as the last
504    /// `OwnedRef` is released.
505    pub fn re_own(&self) -> Option<OwnedRef<T>> {
506        OwnedRef::re_own(Arc::clone(&self.0))
507    }
508}
509
510impl<'a, T> From<&TempRef<'a, T>> for WeakRef<T> {
511    fn from(temp_ref: &TempRef<'a, T>) -> Self {
512        Self(Arc::downgrade(&temp_ref.0))
513    }
514}
515
516impl<'a, T> From<TempRef<'a, T>> for WeakRef<T> {
517    fn from(temp_ref: TempRef<'a, T>) -> Self {
518        Self(Arc::downgrade(&temp_ref.0))
519    }
520}
521
522impl<'a, T> std::ops::Deref for TempRef<'a, T> {
523    type Target = T;
524
525    fn deref(&self) -> &Self::Target {
526        &self.0.deref().value
527    }
528}
529
530impl<'a, T> std::borrow::Borrow<T> for TempRef<'a, T> {
531    fn borrow(&self) -> &T {
532        &self.0.deref().value
533    }
534}
535
536impl<'a, T> std::convert::AsRef<T> for TempRef<'a, T> {
537    fn as_ref(&self) -> &T {
538        &self.0.deref().value
539    }
540}
541
542impl<'a, T: PartialEq> PartialEq for TempRef<'a, T> {
543    fn eq(&self, other: &TempRef<'_, T>) -> bool {
544        Arc::ptr_eq(&self.0, &other.0) || **self == **other
545    }
546}
547
548impl<'a, T: Eq> Eq for TempRef<'a, T> {}
549
550impl<'a, T: PartialOrd> PartialOrd for TempRef<'a, T> {
551    fn partial_cmp(&self, other: &TempRef<'_, T>) -> Option<std::cmp::Ordering> {
552        (**self).partial_cmp(&**other)
553    }
554}
555
556impl<'a, T: Ord> Ord for TempRef<'a, T> {
557    fn cmp(&self, other: &TempRef<'_, T>) -> std::cmp::Ordering {
558        (**self).cmp(&**other)
559    }
560}
561
562impl<'a, T: Hash> Hash for TempRef<'a, T> {
563    fn hash<H: Hasher>(&self, state: &mut H) {
564        (**self).hash(state)
565    }
566}
567
568/// Wrapper around `TempRef` allowing to use it in a Set or as a key of a Map.
569pub struct TempRefKey<'a, T>(pub TempRef<'a, T>);
570impl<'a, T> PartialEq for TempRefKey<'a, T> {
571    fn eq(&self, other: &Self) -> bool {
572        TempRef::ptr_eq(&self.0, &other.0)
573    }
574}
575impl<'a, T> Eq for TempRefKey<'a, T> {}
576impl<'a, T> Hash for TempRefKey<'a, T> {
577    fn hash<H: Hasher>(&self, state: &mut H) {
578        TempRef::as_ptr(&self.0).hash(state);
579    }
580}
581impl<'a, T> std::ops::Deref for TempRefKey<'a, T> {
582    type Target = T;
583    fn deref(&self) -> &Self::Target {
584        self.0.deref()
585    }
586}
587
588/// A wrapper a round a Releasable object that will check, in test and when assertion are enabled,
589/// that the value has been released before being dropped.
590#[must_use = "ReleaseGuard must be released"]
591pub struct ReleaseGuard<T> {
592    /// The wrapped value.
593    value: T,
594
595    /// A guard that will ensure a panic on drop if the ref has not been released.
596    drop_guard: DropGuard,
597}
598
599#[cfg(test)]
600impl<T> ReleaseGuard<T> {
601    pub fn new_released(value: T) -> Self {
602        let result: Self = value.into();
603        result.drop_guard.disarm();
604        result
605    }
606}
607
608impl<T> ReleaseGuard<T> {
609    /// Disarm this release guard.
610    ///
611    /// This will prevent any runtime check that the `value` has been correctly released.
612    pub fn take(this: ReleaseGuard<T>) -> T {
613        this.drop_guard.disarm();
614        this.value
615    }
616}
617
618#[cfg(test)]
619impl<T: Default> ReleaseGuard<T> {
620    pub fn default_released() -> Self {
621        Self::new_released(T::default())
622    }
623}
624
625impl<T: std::fmt::Debug> std::fmt::Debug for ReleaseGuard<T> {
626    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
627        self.value.fmt(f)
628    }
629}
630
631impl<T: Default> Default for ReleaseGuard<T> {
632    fn default() -> Self {
633        T::default().into()
634    }
635}
636
637impl<T: Clone> Clone for ReleaseGuard<T> {
638    fn clone(&self) -> Self {
639        self.value.clone().into()
640    }
641}
642
643impl<T> From<T> for ReleaseGuard<T> {
644    fn from(value: T) -> Self {
645        Self { value, drop_guard: Default::default() }
646    }
647}
648
649impl<T> std::ops::Deref for ReleaseGuard<T> {
650    type Target = T;
651
652    fn deref(&self) -> &Self::Target {
653        &self.value
654    }
655}
656
657impl<T> std::ops::DerefMut for ReleaseGuard<T> {
658    fn deref_mut(&mut self) -> &mut Self::Target {
659        &mut self.value
660    }
661}
662
663impl<T> std::borrow::Borrow<T> for ReleaseGuard<T> {
664    fn borrow(&self) -> &T {
665        self.deref()
666    }
667}
668
669impl<T> std::convert::AsRef<T> for ReleaseGuard<T> {
670    fn as_ref(&self) -> &T {
671        self.deref()
672    }
673}
674
675impl<T: PartialEq> PartialEq for ReleaseGuard<T> {
676    fn eq(&self, other: &ReleaseGuard<T>) -> bool {
677        **self == **other
678    }
679}
680
681impl<T: Eq> Eq for ReleaseGuard<T> {}
682
683impl<T: PartialOrd> PartialOrd for ReleaseGuard<T> {
684    fn partial_cmp(&self, other: &ReleaseGuard<T>) -> Option<std::cmp::Ordering> {
685        (**self).partial_cmp(&**other)
686    }
687}
688
689impl<T: Ord> Ord for ReleaseGuard<T> {
690    fn cmp(&self, other: &ReleaseGuard<T>) -> std::cmp::Ordering {
691        (**self).cmp(&**other)
692    }
693}
694
695impl<T: Hash> Hash for ReleaseGuard<T> {
696    fn hash<H: Hasher>(&self, state: &mut H) {
697        (**self).hash(state)
698    }
699}
700
701#[derive(Default, Debug)]
702pub struct DropGuard {
703    #[cfg(any(test, debug_assertions))]
704    released: std::sync::atomic::AtomicBool,
705}
706
707impl DropGuard {
708    #[inline(always)]
709    pub fn disarm(&self) {
710        #[cfg(any(test, debug_assertions))]
711        {
712            if self
713                .released
714                .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
715                .is_err()
716            {
717                panic!("Guard was disarmed twice");
718            }
719        }
720    }
721}
722
723#[cfg(any(test, debug_assertions))]
724impl Drop for DropGuard {
725    fn drop(&mut self) {
726        assert!(*self.released.get_mut());
727    }
728}
729#[cfg(any(test, debug_assertions))]
730thread_local! {
731    /// Number of `TempRef` in the current thread. This is used to ensure there is no `TempRef`
732    /// while doing a blocking operation.
733    static TEMP_REF_LOCAL_COUNT: std::cell::RefCell<usize> = const { std::cell::RefCell::new(0) };
734}
735
736/// Assert that no temp ref exist on the current thread. This is used before executing a blocking
737/// operation to ensure it will not prevent a OwnedRef release.
738pub fn debug_assert_no_local_temp_ref() {
739    #[cfg(any(test, debug_assertions))]
740    {
741        TEMP_REF_LOCAL_COUNT.with(|count| {
742            assert_eq!(*count.borrow(), 0, "Current threads owns {} TempRef", *count.borrow());
743        });
744    }
745}
746
747/// The internal data of `OwnedRef`/`WeakRef`/`TempRef`.
748///
749/// To ensure that `wait_for_no_ref_once` is correct, the following constraints must apply:
750/// - Once `owned_refs_count` reaches 0, it must never increase again.
751/// - The strong count of `Arc<Self>` must always be incremented before `temp_refs_count` is
752///   incremented.
753/// - Whenever a the strong count of `Arc<Self>` is incremented, `temp_ref_count` must be
754///   increased.
755/// This ensures that `wait_for_no_ref_once` will always be notified when it is waiting on the
756/// `temp_refs_count` futex and the number of `TempRef` reaches 0.
757struct RefInner<T> {
758    /// The underlying value.
759    value: ReleaseGuard<T>,
760    /// The number of `OwnedRef` sharing this data.
761    owned_refs_count: AtomicUsize,
762    /// The number of `TempRef` sharing this data.
763    // This is close to a duplicate of the Arc strong_count, and could be replaced by it if this
764    // module reimplemented all of Arc/Weak. This can be changed without changing the API if this
765    // becomes a performance issue.
766    temp_refs_count: zx::Futex,
767}
768
769impl<T> RefInner<T> {
770    fn new(value: T) -> Self {
771        Self {
772            value: value.into(),
773            owned_refs_count: AtomicUsize::new(1),
774            temp_refs_count: zx::Futex::new(0),
775        }
776    }
777
778    /// Increase `temp_refs_count`. Must be called each time a new `TempRef` is built.
779    fn inc_temp_ref(&self) {
780        self.temp_refs_count.fetch_add(1, Ordering::Relaxed);
781        #[cfg(any(test, debug_assertions))]
782        {
783            TEMP_REF_LOCAL_COUNT.with(|count| {
784                *count.borrow_mut() += 1;
785            });
786        }
787    }
788
789    /// Decrease `temp_refs_count`. Must be called each time a new `TempRef` is dropped.
790    ///
791    /// This will wake the futex on `temp_refs_count` when it reaches 0.
792    fn dec_temp_ref(&self) {
793        let previous_count = self.temp_refs_count.fetch_sub(1, Ordering::Release);
794        if previous_count == 1 {
795            fence(Ordering::Acquire);
796            self.temp_refs_count.wake_single_owner();
797        }
798        #[cfg(any(test, debug_assertions))]
799        {
800            TEMP_REF_LOCAL_COUNT.with(|count| {
801                *count.borrow_mut() -= 1;
802            });
803        }
804    }
805
806    /// Wait for `temp_refs_count` to reach 0 once using the futex.
807    fn wait_for_no_ref_once(self: &Arc<Self>) {
808        // Compute the current number of temp refs, and wait for it to drop to 0.
809        let current_value = self.temp_refs_count.load(Ordering::Acquire);
810        if current_value == 0 {
811            // It is already 0, return.
812            return;
813        }
814        // Otherwise, wait on the futex that will be waken up when the number of temp_ref drops
815        // to 0.
816        let result = self.temp_refs_count.wait(current_value, None, zx::MonotonicInstant::INFINITE);
817        debug_assert!(
818            result == Ok(()) || result == Err(zx::Status::BAD_STATE),
819            "Unexpected result: {result:?}"
820        );
821    }
822}
823
824/// Macro that ensure the releasable is released with the given context if the body returns an
825/// error.
826#[macro_export]
827macro_rules! release_on_error {
828    ($releasable_name:ident, $context:expr, $body:block ) => {{
829        #[allow(clippy::redundant_closure_call)]
830        let result = { (|| $body)() };
831        match result {
832            Err(e) => {
833                $releasable_name.release($context);
834                return Err(e);
835            }
836            Ok(x) => x,
837        }
838    }};
839    ($releasable_name:ident, $body:block ) => {{ release_on_error!($releasable_name, (), $body) }};
840}
841
842/// Macro that ensure the releasable is released with the given context after the body returns.
843#[macro_export]
844macro_rules! release_after {
845    ($releasable_name:ident, $context:expr, async || $($output_type:ty)? $body:block ) => {{
846        #[allow(clippy::redundant_closure_call)]
847        let result = { (async || $(-> $output_type)? { $body })().await };
848        $releasable_name.release($context);
849        result
850    }};
851    ($releasable_name:ident, $context:expr, $(|| -> $output_type:ty)? $body:block ) => {{
852        #[allow(clippy::redundant_closure_call)]
853        let result = { (|| $(-> $output_type)? { $body })() };
854        $releasable_name.release($context);
855        result
856    }};
857    ($releasable_name:ident, async || $($output_type:ty)? $body:block ) => {{
858        release_after!($releasable_name, (), async || $($output_type)? $body)
859    }};
860    ($releasable_name:ident, $(|| -> $output_type:ty)? $body:block ) => {{
861        release_after!($releasable_name, (), $(|| -> $output_type)? $body)
862    }};
863}
864
865/// Macro that ensure the iterator of releasables are released with the given context after
866/// the body returns.
867#[macro_export]
868macro_rules! release_iter_after {
869    ($releasable_iter:ident, $context:expr, async || $(-> $output_type:ty)? $body:block ) => {{
870        #[allow(clippy::redundant_closure_call)]
871        let result = { (async || $(-> $output_type)? { $body })().await };
872        for item in $releasable_iter.into_iter() {
873            item.release($context);
874        }
875        result
876    }};
877    ($releasable_iter:ident, $context:expr, $(|| -> $output_type:ty)? $body:block ) => {{
878        #[allow(clippy::redundant_closure_call)]
879        let result = { (|| $(-> $output_type)? { $body })() };
880        for item in $releasable_iter.into_iter() {
881            item.release($context);
882        }
883        result
884    }};
885}
886
887pub use release_after;
888pub use release_iter_after;
889pub use release_on_error;
890
891#[cfg(test)]
892mod test {
893    use super::*;
894
895    #[derive(Default)]
896    struct Data;
897
898    impl Releasable for Data {
899        type Context<'a> = ();
900        fn release<'a>(self, _: ()) {}
901    }
902
903    #[derive(Default)]
904    struct DataWithMutableReleaseContext;
905
906    impl Releasable for DataWithMutableReleaseContext {
907        type Context<'a> = &'a mut ();
908        fn release<'a>(self, _: &'a mut ()) {}
909    }
910
911    #[::fuchsia::test]
912    #[should_panic]
913    fn drop_without_release() {
914        let _ = OwnedRef::new(Data {});
915    }
916
917    #[::fuchsia::test]
918    fn test_creation_and_reference() {
919        let value = OwnedRef::new(Data {});
920        let reference = WeakRef::from(&value);
921        reference.upgrade().expect("upgrade");
922        value.release(());
923        assert!(reference.upgrade().is_none());
924    }
925
926    #[::fuchsia::test]
927    fn test_clone() {
928        let value = OwnedRef::new(Data {});
929        {
930            let value2 = OwnedRef::share(&value);
931            value2.release(());
932        }
933        #[allow(clippy::redundant_clone)]
934        {
935            let reference = WeakRef::from(&value);
936            let _reference2 = reference.clone();
937        }
938        value.release(());
939    }
940
941    #[::fuchsia::test]
942    fn test_default() {
943        let reference = WeakRef::<Data>::default();
944        assert!(reference.upgrade().is_none());
945    }
946
947    #[::fuchsia::test]
948    fn test_default_as_ptr_is_null() {
949        let reference = WeakRef::<Data>::default();
950        assert!(reference.as_ptr().is_null());
951        assert!(WeakRef::ptr_eq(&reference, &WeakRef::default()));
952    }
953
954    #[::fuchsia::test]
955    fn test_release_on_error() {
956        fn release_on_error() -> Result<(), ()> {
957            let value = OwnedRef::new(Data {});
958            release_on_error!(value, (), {
959                if true {
960                    return Err(());
961                }
962                Ok(())
963            });
964            Ok(())
965        }
966        assert_eq!(release_on_error(), Err(()));
967    }
968
969    #[::fuchsia::test]
970    fn test_into_static() {
971        let value = OwnedRef::new(Data {});
972        let weak = WeakRef::from(&value);
973        // SAFETY: This is safe, as static_ref remains on the stack.
974        let static_ref = TempRef::into_static(weak.upgrade().unwrap());
975        // Check that weak can now be dropped.
976        std::mem::drop(weak);
977        // Drop static_ref
978        std::mem::drop(static_ref);
979        value.release(());
980    }
981
982    #[::fuchsia::test]
983    fn test_debug_assert_no_local_temp_ref() {
984        debug_assert_no_local_temp_ref();
985        let value = OwnedRef::new(Data {});
986        debug_assert_no_local_temp_ref();
987        let _temp_ref = OwnedRef::temp(&value);
988        std::thread::spawn(|| {
989            debug_assert_no_local_temp_ref();
990        })
991        .join()
992        .expect("join");
993        std::mem::drop(_temp_ref);
994        debug_assert_no_local_temp_ref();
995        value.release(());
996        debug_assert_no_local_temp_ref();
997    }
998
999    #[::fuchsia::test]
1000    #[should_panic]
1001    fn test_debug_assert_no_local_temp_ref_aborts() {
1002        let value = OwnedRef::new(Data {});
1003        {
1004            let _temp_ref = OwnedRef::temp(&value);
1005            debug_assert_no_local_temp_ref();
1006        }
1007        // This code should not be reached, but ensures the test will fail is
1008        // `debug_assert_no_local_temp_ref` fails to panic.
1009        value.release(());
1010    }
1011
1012    #[::fuchsia::test]
1013    #[should_panic]
1014    fn test_unrelease_release_guard() {
1015        let _value = ReleaseGuard::<Data>::default();
1016    }
1017
1018    #[::fuchsia::test]
1019    fn test_released_release_guard() {
1020        let _value = ReleaseGuard::<Data>::default_released();
1021    }
1022
1023    #[::fuchsia::test]
1024    fn release_with_mutable_context() {
1025        let value = OwnedRef::new(DataWithMutableReleaseContext {});
1026        let mut context = ();
1027        value.release(&mut context);
1028    }
1029
1030    // If this test fails, it will almost always be with a very low probability. Any failure is a
1031    // real, high priority bug.
1032    #[::fuchsia::test]
1033    fn upgrade_while_release() {
1034        let value = OwnedRef::new(Data {});
1035        // Run 10 threads trying to upgrade a weak pointer in a loop.
1036        for _ in 0..10 {
1037            std::thread::spawn({
1038                let weak = OwnedRef::downgrade(&value);
1039                move || loop {
1040                    if weak.upgrade().is_none() {
1041                        return;
1042                    }
1043                }
1044            });
1045        }
1046        // Release the value after letting the threads make some progress.
1047        std::thread::sleep(std::time::Duration::from_millis(10));
1048        value.release(());
1049        // The test must finish, and no assertion should trigger.
1050    }
1051
1052    #[::fuchsia::test]
1053    fn new_cyclic() {
1054        let mut weak_value = None;
1055        let value = OwnedRef::new_cyclic(|weak| {
1056            weak_value = Some(weak);
1057            Data {}
1058        });
1059        let weak_value = weak_value.expect("weak_value");
1060        assert!(weak_value.upgrade().is_some());
1061        value.release(());
1062        assert!(weak_value.upgrade().is_none());
1063    }
1064
1065    #[::fuchsia::test]
1066    fn as_ptr() {
1067        let value = OwnedRef::new(Data {});
1068        let weak = OwnedRef::downgrade(&value);
1069        let temp = weak.upgrade().expect("upgrade");
1070        assert_eq!(OwnedRef::as_ptr(&value), weak.as_ptr());
1071        assert_eq!(OwnedRef::as_ptr(&value), TempRef::as_ptr(&temp));
1072        std::mem::drop(temp);
1073        value.release(());
1074    }
1075
1076    #[::fuchsia::test]
1077    fn test_re_own() {
1078        let data = Data::default();
1079        let owned = OwnedRef::new(data);
1080        let weak = WeakRef::from(&owned);
1081
1082        let re_owned = weak.re_own();
1083        assert!(re_owned.is_some());
1084
1085        // Release the original owned ref.
1086        owned.release(());
1087
1088        // The re_owned ref is still alive.
1089        let re_owned_again = weak.re_own();
1090        assert!(re_owned_again.is_some());
1091        re_owned_again.release(());
1092
1093        // Now release the first re-owned ref.
1094        re_owned.release(());
1095
1096        // Now that all owned refs are released, re_own should fail.
1097        let re_owned_finally = weak.re_own();
1098        assert!(re_owned_finally.is_none());
1099    }
1100
1101    #[::fuchsia::test]
1102    fn test_re_own_concurrent() {
1103        let owned = OwnedRef::new(Data::default());
1104        let weak = WeakRef::from(&owned);
1105        let num_threads = 10;
1106
1107        let mut handles = vec![];
1108        for _ in 0..num_threads {
1109            let weak = weak.clone();
1110            let handle = std::thread::spawn(move || {
1111                loop {
1112                    if let Some(re_owned) = weak.re_own() {
1113                        re_owned.release(());
1114                    } else {
1115                        return;
1116                    }
1117                }
1118            });
1119            handles.push(handle);
1120        }
1121
1122        owned.release(());
1123
1124        for handle in handles {
1125            handle.join().unwrap();
1126        }
1127
1128        assert!(weak.re_own().is_none());
1129    }
1130
1131    #[::fuchsia::test]
1132    fn test_release_after() {
1133        let owned = OwnedRef::new(Data::default());
1134        let value = release_after!(owned, (), { 0 });
1135        assert_eq!(value, 0);
1136    }
1137
1138    #[::fuchsia::test]
1139    async fn test_release_after_async() {
1140        let owned = OwnedRef::new(Data::default());
1141        let value = release_after!(owned, (), async || { 0 });
1142        assert_eq!(value, 0);
1143    }
1144}