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>.
361    ///
362    /// See `Weak::as_ptr`
363    pub fn as_ptr(&self) -> *const T {
364        let base = self.0.as_ptr();
365        let value = memoffset::raw_field!(base, RefInner<T>, value);
366        memoffset::raw_field!(value, ReleaseGuard<T>, value)
367    }
368
369    /// Returns true if the two objects point to the same allocation
370    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
371        Self::as_ptr(this) == Self::as_ptr(other)
372    }
373}
374
375impl<T> Default for WeakRef<T> {
376    fn default() -> Self {
377        Self::new()
378    }
379}
380
381impl<T> Clone for WeakRef<T> {
382    fn clone(&self) -> Self {
383        Self(self.0.clone())
384    }
385}
386
387impl<T> PartialEq for WeakRef<T> {
388    fn eq(&self, other: &Self) -> bool {
389        WeakRef::ptr_eq(self, other)
390    }
391}
392
393/// Wrapper around `WeakRef` allowing to use it in a Set or as a key of a Map.
394pub struct WeakRefKey<T>(pub WeakRef<T>);
395impl<T> PartialEq for WeakRefKey<T> {
396    fn eq(&self, other: &Self) -> bool {
397        WeakRef::ptr_eq(&self.0, &other.0)
398    }
399}
400impl<T> PartialOrd for WeakRefKey<T> {
401    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
402        Some(self.cmp(other))
403    }
404}
405impl<T> Ord for WeakRefKey<T> {
406    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
407        WeakRef::as_ptr(&self.0).cmp(&WeakRef::as_ptr(&other.0))
408    }
409}
410impl<T> From<WeakRef<T>> for WeakRefKey<T> {
411    fn from(weak_ref: WeakRef<T>) -> Self {
412        Self(weak_ref)
413    }
414}
415impl<'a, T> From<&TempRef<'a, T>> for WeakRefKey<T> {
416    fn from(temp_ref: &TempRef<'a, T>) -> Self {
417        Self(WeakRef::from(temp_ref))
418    }
419}
420impl<'a, T> From<&OwnedRef<T>> for WeakRefKey<T> {
421    fn from(owned_ref: &OwnedRef<T>) -> Self {
422        Self(WeakRef::from(owned_ref))
423    }
424}
425impl<T> Clone for WeakRefKey<T> {
426    fn clone(&self) -> Self {
427        Self(self.0.clone())
428    }
429}
430impl<T> Eq for WeakRefKey<T> {}
431impl<T> Hash for WeakRefKey<T> {
432    fn hash<H: Hasher>(&self, state: &mut H) {
433        WeakRef::as_ptr(&self.0).hash(state);
434    }
435}
436impl<T> std::ops::Deref for WeakRefKey<T> {
437    type Target = WeakRef<T>;
438    fn deref(&self) -> &Self::Target {
439        &self.0
440    }
441}
442impl<T> std::fmt::Debug for WeakRefKey<T> {
443    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
444        fmt.debug_tuple(std::any::type_name::<Self>()).field(&self.0.as_ptr()).finish()
445    }
446}
447
448/// A temporary reference to a shared owned object. This permits access to the shared object, but
449/// will block any thread trying to release the last `OwnedRef`. As such, such reference must be
450/// released as soon as possible. In particular, one must not do any blocking operation while
451/// owning such a refeence.
452// Until negative trait bound are implemented, using `*mut u8` to prevent transferring TempRef
453// across threads.
454pub struct TempRef<'a, T>(Arc<RefInner<T>>, std::marker::PhantomData<(&'a T, *mut u8)>);
455
456impl<'a, T> std::fmt::Debug for TempRef<'a, T>
457where
458    T: std::fmt::Debug,
459{
460    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461        self.deref().fmt(f)
462    }
463}
464
465impl<'a, T> Drop for TempRef<'a, T> {
466    fn drop(&mut self) {
467        self.0.dec_temp_ref();
468    }
469}
470
471impl<'a, T> TempRef<'a, T> {
472    /// Build a new TempRef. Ensures `temp_refs_count` is correctly updated.
473    fn new(inner: Arc<RefInner<T>>) -> Self {
474        inner.inc_temp_ref();
475        Self(inner, Default::default())
476    }
477
478    /// Provides a raw pointer to the data.
479    ///
480    /// See `Arc::as_ptr`
481    pub fn as_ptr(this: &Self) -> *const T {
482        &this.0.value.value as *const T
483    }
484
485    /// Returns true if the two objects point to the same allocation
486    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
487        Self::as_ptr(this) == Self::as_ptr(other)
488    }
489
490    /// This allows to change the lifetime annotation of a `TempRef` to static.
491    ///
492    /// As `TempRef` must be dropped as soon as possible, this provided the way to block the release
493    /// of the related `OwnedRef`s and as such is considered sensitive. Any caller must ensure that
494    /// the returned `TempRef` is not kept around while doing blocking calls.
495    pub fn into_static(this: Self) -> TempRef<'static, T> {
496        TempRef::new(this.0.clone())
497    }
498
499    /// Try to upgrade the `WeakRef` into a `OwnedRef`. This will fail as soon as the last
500    /// `OwnedRef` is released.
501    pub fn re_own(&self) -> Option<OwnedRef<T>> {
502        OwnedRef::re_own(Arc::clone(&self.0))
503    }
504}
505
506impl<'a, T> From<&TempRef<'a, T>> for WeakRef<T> {
507    fn from(temp_ref: &TempRef<'a, T>) -> Self {
508        Self(Arc::downgrade(&temp_ref.0))
509    }
510}
511
512impl<'a, T> From<TempRef<'a, T>> for WeakRef<T> {
513    fn from(temp_ref: TempRef<'a, T>) -> Self {
514        Self(Arc::downgrade(&temp_ref.0))
515    }
516}
517
518impl<'a, T> std::ops::Deref for TempRef<'a, T> {
519    type Target = T;
520
521    fn deref(&self) -> &Self::Target {
522        &self.0.deref().value
523    }
524}
525
526impl<'a, T> std::borrow::Borrow<T> for TempRef<'a, T> {
527    fn borrow(&self) -> &T {
528        &self.0.deref().value
529    }
530}
531
532impl<'a, T> std::convert::AsRef<T> for TempRef<'a, T> {
533    fn as_ref(&self) -> &T {
534        &self.0.deref().value
535    }
536}
537
538impl<'a, T: PartialEq> PartialEq for TempRef<'a, T> {
539    fn eq(&self, other: &TempRef<'_, T>) -> bool {
540        Arc::ptr_eq(&self.0, &other.0) || **self == **other
541    }
542}
543
544impl<'a, T: Eq> Eq for TempRef<'a, T> {}
545
546impl<'a, T: PartialOrd> PartialOrd for TempRef<'a, T> {
547    fn partial_cmp(&self, other: &TempRef<'_, T>) -> Option<std::cmp::Ordering> {
548        (**self).partial_cmp(&**other)
549    }
550}
551
552impl<'a, T: Ord> Ord for TempRef<'a, T> {
553    fn cmp(&self, other: &TempRef<'_, T>) -> std::cmp::Ordering {
554        (**self).cmp(&**other)
555    }
556}
557
558impl<'a, T: Hash> Hash for TempRef<'a, T> {
559    fn hash<H: Hasher>(&self, state: &mut H) {
560        (**self).hash(state)
561    }
562}
563
564/// Wrapper around `TempRef` allowing to use it in a Set or as a key of a Map.
565pub struct TempRefKey<'a, T>(pub TempRef<'a, T>);
566impl<'a, T> PartialEq for TempRefKey<'a, T> {
567    fn eq(&self, other: &Self) -> bool {
568        TempRef::ptr_eq(&self.0, &other.0)
569    }
570}
571impl<'a, T> Eq for TempRefKey<'a, T> {}
572impl<'a, T> Hash for TempRefKey<'a, T> {
573    fn hash<H: Hasher>(&self, state: &mut H) {
574        TempRef::as_ptr(&self.0).hash(state);
575    }
576}
577impl<'a, T> std::ops::Deref for TempRefKey<'a, T> {
578    type Target = T;
579    fn deref(&self) -> &Self::Target {
580        self.0.deref()
581    }
582}
583
584/// A wrapper a round a Releasable object that will check, in test and when assertion are enabled,
585/// that the value has been released before being dropped.
586#[must_use = "ReleaseGuard must be released"]
587pub struct ReleaseGuard<T> {
588    /// The wrapped value.
589    value: T,
590
591    /// A guard that will ensure a panic on drop if the ref has not been released.
592    drop_guard: DropGuard,
593}
594
595#[cfg(test)]
596impl<T> ReleaseGuard<T> {
597    pub fn new_released(value: T) -> Self {
598        let result: Self = value.into();
599        result.drop_guard.disarm();
600        result
601    }
602}
603
604impl<T> ReleaseGuard<T> {
605    /// Disarm this release guard.
606    ///
607    /// This will prevent any runtime check that the `value` has been correctly released.
608    pub fn take(this: ReleaseGuard<T>) -> T {
609        this.drop_guard.disarm();
610        this.value
611    }
612}
613
614#[cfg(test)]
615impl<T: Default> ReleaseGuard<T> {
616    pub fn default_released() -> Self {
617        Self::new_released(T::default())
618    }
619}
620
621impl<T: std::fmt::Debug> std::fmt::Debug for ReleaseGuard<T> {
622    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
623        self.value.fmt(f)
624    }
625}
626
627impl<T: Default> Default for ReleaseGuard<T> {
628    fn default() -> Self {
629        T::default().into()
630    }
631}
632
633impl<T: Clone> Clone for ReleaseGuard<T> {
634    fn clone(&self) -> Self {
635        self.value.clone().into()
636    }
637}
638
639impl<T> From<T> for ReleaseGuard<T> {
640    fn from(value: T) -> Self {
641        Self { value, drop_guard: Default::default() }
642    }
643}
644
645impl<T> std::ops::Deref for ReleaseGuard<T> {
646    type Target = T;
647
648    fn deref(&self) -> &Self::Target {
649        &self.value
650    }
651}
652
653impl<T> std::ops::DerefMut for ReleaseGuard<T> {
654    fn deref_mut(&mut self) -> &mut Self::Target {
655        &mut self.value
656    }
657}
658
659impl<T> std::borrow::Borrow<T> for ReleaseGuard<T> {
660    fn borrow(&self) -> &T {
661        self.deref()
662    }
663}
664
665impl<T> std::convert::AsRef<T> for ReleaseGuard<T> {
666    fn as_ref(&self) -> &T {
667        self.deref()
668    }
669}
670
671impl<T: PartialEq> PartialEq for ReleaseGuard<T> {
672    fn eq(&self, other: &ReleaseGuard<T>) -> bool {
673        **self == **other
674    }
675}
676
677impl<T: Eq> Eq for ReleaseGuard<T> {}
678
679impl<T: PartialOrd> PartialOrd for ReleaseGuard<T> {
680    fn partial_cmp(&self, other: &ReleaseGuard<T>) -> Option<std::cmp::Ordering> {
681        (**self).partial_cmp(&**other)
682    }
683}
684
685impl<T: Ord> Ord for ReleaseGuard<T> {
686    fn cmp(&self, other: &ReleaseGuard<T>) -> std::cmp::Ordering {
687        (**self).cmp(&**other)
688    }
689}
690
691impl<T: Hash> Hash for ReleaseGuard<T> {
692    fn hash<H: Hasher>(&self, state: &mut H) {
693        (**self).hash(state)
694    }
695}
696
697#[derive(Default, Debug)]
698pub struct DropGuard {
699    #[cfg(any(test, debug_assertions))]
700    released: std::sync::atomic::AtomicBool,
701}
702
703impl DropGuard {
704    #[inline(always)]
705    pub fn disarm(&self) {
706        #[cfg(any(test, debug_assertions))]
707        {
708            if self
709                .released
710                .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
711                .is_err()
712            {
713                panic!("Guard was disarmed twice");
714            }
715        }
716    }
717}
718
719#[cfg(any(test, debug_assertions))]
720impl Drop for DropGuard {
721    fn drop(&mut self) {
722        assert!(*self.released.get_mut());
723    }
724}
725#[cfg(any(test, debug_assertions))]
726thread_local! {
727    /// Number of `TempRef` in the current thread. This is used to ensure there is no `TempRef`
728    /// while doing a blocking operation.
729    static TEMP_REF_LOCAL_COUNT: std::cell::RefCell<usize> = const { std::cell::RefCell::new(0) };
730}
731
732/// Assert that no temp ref exist on the current thread. This is used before executing a blocking
733/// operation to ensure it will not prevent a OwnedRef release.
734pub fn debug_assert_no_local_temp_ref() {
735    #[cfg(any(test, debug_assertions))]
736    {
737        TEMP_REF_LOCAL_COUNT.with(|count| {
738            assert_eq!(*count.borrow(), 0, "Current threads owns {} TempRef", *count.borrow());
739        });
740    }
741}
742
743/// The internal data of `OwnedRef`/`WeakRef`/`TempRef`.
744///
745/// To ensure that `wait_for_no_ref_once` is correct, the following constraints must apply:
746/// - Once `owned_refs_count` reaches 0, it must never increase again.
747/// - The strong count of `Arc<Self>` must always be incremented before `temp_refs_count` is
748///   incremented.
749/// - Whenever a the strong count of `Arc<Self>` is incremented, `temp_ref_count` must be
750///   increased.
751/// This ensures that `wait_for_no_ref_once` will always be notified when it is waiting on the
752/// `temp_refs_count` futex and the number of `TempRef` reaches 0.
753struct RefInner<T> {
754    /// The underlying value.
755    value: ReleaseGuard<T>,
756    /// The number of `OwnedRef` sharing this data.
757    owned_refs_count: AtomicUsize,
758    /// The number of `TempRef` sharing this data.
759    // This is close to a duplicate of the Arc strong_count, and could be replaced by it if this
760    // module reimplemented all of Arc/Weak. This can be changed without changing the API if this
761    // becomes a performance issue.
762    temp_refs_count: zx::Futex,
763}
764
765impl<T> RefInner<T> {
766    fn new(value: T) -> Self {
767        Self {
768            value: value.into(),
769            owned_refs_count: AtomicUsize::new(1),
770            temp_refs_count: zx::Futex::new(0),
771        }
772    }
773
774    /// Increase `temp_refs_count`. Must be called each time a new `TempRef` is built.
775    fn inc_temp_ref(&self) {
776        self.temp_refs_count.fetch_add(1, Ordering::Relaxed);
777        #[cfg(any(test, debug_assertions))]
778        {
779            TEMP_REF_LOCAL_COUNT.with(|count| {
780                *count.borrow_mut() += 1;
781            });
782        }
783    }
784
785    /// Decrease `temp_refs_count`. Must be called each time a new `TempRef` is dropped.
786    ///
787    /// This will wake the futex on `temp_refs_count` when it reaches 0.
788    fn dec_temp_ref(&self) {
789        let previous_count = self.temp_refs_count.fetch_sub(1, Ordering::Release);
790        if previous_count == 1 {
791            fence(Ordering::Acquire);
792            self.temp_refs_count.wake_single_owner();
793        }
794        #[cfg(any(test, debug_assertions))]
795        {
796            TEMP_REF_LOCAL_COUNT.with(|count| {
797                *count.borrow_mut() -= 1;
798            });
799        }
800    }
801
802    /// Wait for `temp_refs_count` to reach 0 once using the futex.
803    fn wait_for_no_ref_once(self: &Arc<Self>) {
804        // Compute the current number of temp refs, and wait for it to drop to 0.
805        let current_value = self.temp_refs_count.load(Ordering::Acquire);
806        if current_value == 0 {
807            // It is already 0, return.
808            return;
809        }
810        // Otherwise, wait on the futex that will be waken up when the number of temp_ref drops
811        // to 0.
812        let result = self.temp_refs_count.wait(current_value, None, zx::MonotonicInstant::INFINITE);
813        debug_assert!(
814            result == Ok(()) || result == Err(zx::Status::BAD_STATE),
815            "Unexpected result: {result:?}"
816        );
817    }
818}
819
820/// Macro that ensure the releasable is released with the given context if the body returns an
821/// error.
822#[macro_export]
823macro_rules! release_on_error {
824    ($releasable_name:ident, $context:expr, $body:block ) => {{
825        #[allow(clippy::redundant_closure_call)]
826        let result = { (|| $body)() };
827        match result {
828            Err(e) => {
829                $releasable_name.release($context);
830                return Err(e);
831            }
832            Ok(x) => x,
833        }
834    }};
835    ($releasable_name:ident, $body:block ) => {{ release_on_error!($releasable_name, (), $body) }};
836}
837
838/// Macro that ensure the releasable is released with the given context after the body returns.
839#[macro_export]
840macro_rules! release_after {
841    ($releasable_name:ident, $context:expr, async || $($output_type:ty)? $body:block ) => {{
842        #[allow(clippy::redundant_closure_call)]
843        let result = { (async || $(-> $output_type)? { $body })().await };
844        $releasable_name.release($context);
845        result
846    }};
847    ($releasable_name:ident, $context:expr, $(|| -> $output_type:ty)? $body:block ) => {{
848        #[allow(clippy::redundant_closure_call)]
849        let result = { (|| $(-> $output_type)? { $body })() };
850        $releasable_name.release($context);
851        result
852    }};
853    ($releasable_name:ident, async || $($output_type:ty)? $body:block ) => {{
854        release_after!($releasable_name, (), async || $($output_type)? $body)
855    }};
856    ($releasable_name:ident, $(|| -> $output_type:ty)? $body:block ) => {{
857        release_after!($releasable_name, (), $(|| -> $output_type)? $body)
858    }};
859}
860
861/// Macro that ensure the iterator of releasables are released with the given context after
862/// the body returns.
863#[macro_export]
864macro_rules! release_iter_after {
865    ($releasable_iter:ident, $context:expr, async || $(-> $output_type:ty)? $body:block ) => {{
866        #[allow(clippy::redundant_closure_call)]
867        let result = { (async || $(-> $output_type)? { $body })().await };
868        for item in $releasable_iter.into_iter() {
869            item.release($context);
870        }
871        result
872    }};
873    ($releasable_iter:ident, $context:expr, $(|| -> $output_type:ty)? $body:block ) => {{
874        #[allow(clippy::redundant_closure_call)]
875        let result = { (|| $(-> $output_type)? { $body })() };
876        for item in $releasable_iter.into_iter() {
877            item.release($context);
878        }
879        result
880    }};
881}
882
883pub use release_after;
884pub use release_iter_after;
885pub use release_on_error;
886
887#[cfg(test)]
888mod test {
889    use super::*;
890
891    #[derive(Default)]
892    struct Data;
893
894    impl Releasable for Data {
895        type Context<'a> = ();
896        fn release<'a>(self, _: ()) {}
897    }
898
899    #[derive(Default)]
900    struct DataWithMutableReleaseContext;
901
902    impl Releasable for DataWithMutableReleaseContext {
903        type Context<'a> = &'a mut ();
904        fn release<'a>(self, _: &'a mut ()) {}
905    }
906
907    #[::fuchsia::test]
908    #[should_panic]
909    fn drop_without_release() {
910        let _ = OwnedRef::new(Data {});
911    }
912
913    #[::fuchsia::test]
914    fn test_creation_and_reference() {
915        let value = OwnedRef::new(Data {});
916        let reference = WeakRef::from(&value);
917        reference.upgrade().expect("upgrade");
918        value.release(());
919        assert!(reference.upgrade().is_none());
920    }
921
922    #[::fuchsia::test]
923    fn test_clone() {
924        let value = OwnedRef::new(Data {});
925        {
926            let value2 = OwnedRef::share(&value);
927            value2.release(());
928        }
929        #[allow(clippy::redundant_clone)]
930        {
931            let reference = WeakRef::from(&value);
932            let _reference2 = reference.clone();
933        }
934        value.release(());
935    }
936
937    #[::fuchsia::test]
938    fn test_default() {
939        let reference = WeakRef::<Data>::default();
940        assert!(reference.upgrade().is_none());
941    }
942
943    #[::fuchsia::test]
944    fn test_release_on_error() {
945        fn release_on_error() -> Result<(), ()> {
946            let value = OwnedRef::new(Data {});
947            release_on_error!(value, (), {
948                if true {
949                    return Err(());
950                }
951                Ok(())
952            });
953            Ok(())
954        }
955        assert_eq!(release_on_error(), Err(()));
956    }
957
958    #[::fuchsia::test]
959    fn test_into_static() {
960        let value = OwnedRef::new(Data {});
961        let weak = WeakRef::from(&value);
962        // SAFETY: This is safe, as static_ref remains on the stack.
963        let static_ref = TempRef::into_static(weak.upgrade().unwrap());
964        // Check that weak can now be dropped.
965        std::mem::drop(weak);
966        // Drop static_ref
967        std::mem::drop(static_ref);
968        value.release(());
969    }
970
971    #[::fuchsia::test]
972    fn test_debug_assert_no_local_temp_ref() {
973        debug_assert_no_local_temp_ref();
974        let value = OwnedRef::new(Data {});
975        debug_assert_no_local_temp_ref();
976        let _temp_ref = OwnedRef::temp(&value);
977        std::thread::spawn(|| {
978            debug_assert_no_local_temp_ref();
979        })
980        .join()
981        .expect("join");
982        std::mem::drop(_temp_ref);
983        debug_assert_no_local_temp_ref();
984        value.release(());
985        debug_assert_no_local_temp_ref();
986    }
987
988    #[::fuchsia::test]
989    #[should_panic]
990    fn test_debug_assert_no_local_temp_ref_aborts() {
991        let value = OwnedRef::new(Data {});
992        {
993            let _temp_ref = OwnedRef::temp(&value);
994            debug_assert_no_local_temp_ref();
995        }
996        // This code should not be reached, but ensures the test will fail is
997        // `debug_assert_no_local_temp_ref` fails to panic.
998        value.release(());
999    }
1000
1001    #[::fuchsia::test]
1002    #[should_panic]
1003    fn test_unrelease_release_guard() {
1004        let _value = ReleaseGuard::<Data>::default();
1005    }
1006
1007    #[::fuchsia::test]
1008    fn test_released_release_guard() {
1009        let _value = ReleaseGuard::<Data>::default_released();
1010    }
1011
1012    #[::fuchsia::test]
1013    fn release_with_mutable_context() {
1014        let value = OwnedRef::new(DataWithMutableReleaseContext {});
1015        let mut context = ();
1016        value.release(&mut context);
1017    }
1018
1019    // If this test fails, it will almost always be with a very low probability. Any failure is a
1020    // real, high priority bug.
1021    #[::fuchsia::test]
1022    fn upgrade_while_release() {
1023        let value = OwnedRef::new(Data {});
1024        // Run 10 threads trying to upgrade a weak pointer in a loop.
1025        for _ in 0..10 {
1026            std::thread::spawn({
1027                let weak = OwnedRef::downgrade(&value);
1028                move || loop {
1029                    if weak.upgrade().is_none() {
1030                        return;
1031                    }
1032                }
1033            });
1034        }
1035        // Release the value after letting the threads make some progress.
1036        std::thread::sleep(std::time::Duration::from_millis(10));
1037        value.release(());
1038        // The test must finish, and no assertion should trigger.
1039    }
1040
1041    #[::fuchsia::test]
1042    fn new_cyclic() {
1043        let mut weak_value = None;
1044        let value = OwnedRef::new_cyclic(|weak| {
1045            weak_value = Some(weak);
1046            Data {}
1047        });
1048        let weak_value = weak_value.expect("weak_value");
1049        assert!(weak_value.upgrade().is_some());
1050        value.release(());
1051        assert!(weak_value.upgrade().is_none());
1052    }
1053
1054    #[::fuchsia::test]
1055    fn as_ptr() {
1056        let value = OwnedRef::new(Data {});
1057        let weak = OwnedRef::downgrade(&value);
1058        let temp = weak.upgrade().expect("upgrade");
1059        assert_eq!(OwnedRef::as_ptr(&value), weak.as_ptr());
1060        assert_eq!(OwnedRef::as_ptr(&value), TempRef::as_ptr(&temp));
1061        std::mem::drop(temp);
1062        value.release(());
1063    }
1064
1065    #[::fuchsia::test]
1066    fn test_re_own() {
1067        let data = Data::default();
1068        let owned = OwnedRef::new(data);
1069        let weak = WeakRef::from(&owned);
1070
1071        let re_owned = weak.re_own();
1072        assert!(re_owned.is_some());
1073
1074        // Release the original owned ref.
1075        owned.release(());
1076
1077        // The re_owned ref is still alive.
1078        let re_owned_again = weak.re_own();
1079        assert!(re_owned_again.is_some());
1080        re_owned_again.release(());
1081
1082        // Now release the first re-owned ref.
1083        re_owned.release(());
1084
1085        // Now that all owned refs are released, re_own should fail.
1086        let re_owned_finally = weak.re_own();
1087        assert!(re_owned_finally.is_none());
1088    }
1089
1090    #[::fuchsia::test]
1091    fn test_re_own_concurrent() {
1092        let owned = OwnedRef::new(Data::default());
1093        let weak = WeakRef::from(&owned);
1094        let num_threads = 10;
1095
1096        let mut handles = vec![];
1097        for _ in 0..num_threads {
1098            let weak = weak.clone();
1099            let handle = std::thread::spawn(move || {
1100                loop {
1101                    if let Some(re_owned) = weak.re_own() {
1102                        re_owned.release(());
1103                    } else {
1104                        return;
1105                    }
1106                }
1107            });
1108            handles.push(handle);
1109        }
1110
1111        owned.release(());
1112
1113        for handle in handles {
1114            handle.join().unwrap();
1115        }
1116
1117        assert!(weak.re_own().is_none());
1118    }
1119
1120    #[::fuchsia::test]
1121    fn test_release_after() {
1122        let owned = OwnedRef::new(Data::default());
1123        let value = release_after!(owned, (), { 0 });
1124        assert_eq!(value, 0);
1125    }
1126
1127    #[::fuchsia::test]
1128    async fn test_release_after_async() {
1129        let owned = OwnedRef::new(Data::default());
1130        let value = release_after!(owned, (), async || { 0 });
1131        assert_eq!(value, 0);
1132    }
1133}