Skip to main content

cocoon_tpm_utils_async/alloc/
sync_vec.rs

1extern crate alloc;
2use alloc::vec::Vec;
3
4use crate::sync_types;
5use core::{marker, ops};
6
7/// Error returned by [`SyncVec::try_reserve()`] and
8/// [`SyncVec::try_reserve_exact()`].
9#[derive(Debug)]
10pub enum SyncVecError {
11    /// The memory allocation has failed.
12    MemoryAllocationFailure,
13}
14
15/// [`Lock`](sync_types::Lock)-protectable [`Vec`] proxy with support for
16/// unlocked reallocations.
17///
18/// As an execution environment's [`Lock`](sync_types::Lock) implementation
19/// might be of the spinlock kind, memory allocations under such a lock are to
20/// be avoided. `SyncVec` implements a common "Read-Copy-Update" style pattern
21/// for resizing a Rust core [`Vec`]: the lock will get dropped for a
22/// memory allocation, reacquired afterwards and the original [`Vec`] replaced
23/// with the resized one under the reacquired lock.
24///
25/// Note that in order to support [`LockForInner`](sync_types::LockForInner)
26/// scenarios, `SyncVec` does not wrap the managed [`Vec`] in
27/// [`Lock`](sync_types::Lock) by itself: it is expected that users of `SyncVec`
28/// wrap it or an ancestor in the data structure hiearchy in one.
29///
30/// Even though the inner [`Vec`] is fully exposed via
31/// [`DerefMut`](ops::DerefMut), users should refrain from using
32/// [`Vec::try_reserve()`](Vec::try_reserve) or
33/// [`Vec::try_reserve_exact()`](Vec::try_reserve_exact) directly through a
34/// [`locking guard`](sync_types::Lock::Guard), either explictly or implicitly
35/// through e.g. a [`Vec::resize()`](Vec::resize) on a [`Vec`] with insufficient
36/// capcacity.
37pub struct SyncVec<T: marker::Send> {
38    /// The managed [`Vec`] instance.
39    v: Vec<T>,
40    /// Sum of the requested additional capacities of all currently pending
41    /// concurrent [`try_reserve_impl()`](Self::try_reserve_impl) requests.
42    pending_reservations_additional_capacity: usize,
43}
44
45impl<T: marker::Send> SyncVec<T> {
46    /// Create a new empty `SyncVec`.
47    pub fn new() -> Self {
48        Self {
49            v: Vec::new(),
50            pending_reservations_additional_capacity: 0,
51        }
52    }
53
54    /// Wrapper to [`Vec::try_reserve_exact()`](Vec::try_reserve_exact) with
55    /// lock management support.
56    ///
57    /// To be called with the protecting [`Lock`](sync_types::Lock) locked.  The
58    /// corresponding locking `guard` is to be handed over by the caller and
59    /// will get returned back. ** Note that the `guard` may get dropped and
60    /// reacquired in the course, so any state protected by the
61    /// [`Lock`](sync_types::Lock) must get reread and reevaluated by the
62    /// caller!**. Moreover, the capacity reservation is valid only for the
63    /// lifetime of the returned guard. Details follow.
64    ///
65    /// If the underlying `Vec`'s capacity is already sufficient, nothing is to
66    /// be done and the original `guard` would simply get returned back.
67    /// Otherwise
68    /// * the guard will get dropped,
69    /// * memory of size sufficient to hold a [`Vec`] with the additional
70    ///   requested capacity allocated outside the lock and
71    /// * the lock gets reacquired,
72    /// * if the memory allocation was successful, the original [`Vec`]'s
73    ///   elements get moved into the new memory,
74    /// * the guard for the *reacquired* lock gets returned back to the caller.
75    ///
76    /// Furthermore, there are provisions to handle multiple concurrent
77    /// reservations correctly.
78    ///
79    /// # Arguments:
80    ///
81    /// * `this` - The [`Lock`](sync_types::Lock) rotecting the `SyncVec`
82    ///   instance.
83    /// * `guard` - [`Locking guard`](sync_types::Lock::Guard) for `this`. Will
84    ///   get returned back to the caller on success, **but might have been
85    ///   dropped and reacquired in the course**.
86    /// * `additional_capacity` - The additional capacity to reserve. On
87    ///   success, the underlying `Vec` is guaranteed to have storage sufficient
88    ///   to hold that many additional elements without any reallocation, as
89    ///   long as the [`Locking guard`](sync_types::Lock::Guard) is alive.
90    pub fn try_reserve_exact<'a, L: sync_types::Lock<Self>>(
91        this: &'a L,
92        guard: L::Guard<'a>,
93        additional_capacity: usize,
94    ) -> (L::Guard<'a>, Result<(), SyncVecError>) {
95        Self::try_reserve_impl(this, guard, additional_capacity, true)
96    }
97
98    /// Wrapper to [`Vec::try_reserve()`](Vec::try_reserve) with lock management
99    /// support.
100    ///
101    /// To be called with the protecting [`Lock`](sync_types::Lock) locked.  The
102    /// corresponding locking `guard` is to be handed over by the caller and
103    /// will get returned back. ** Note that the `guard` may get dropped and
104    /// reacquired in the course, so any state protected by the
105    /// [`Lock`](sync_types::Lock) must get reread and reevaluated by the
106    /// caller!**. Moreover, the capacity reservation is valid only for the
107    /// lifetime of the returned guard. Details follow.
108    ///
109    /// If the underlying `Vec`'s capacity is already sufficient, nothing is to
110    /// be done and the original `guard` would simply get returned back.
111    /// Otherwise
112    /// * the guard will get dropped,
113    /// * memory of size sufficient to hold a [`Vec`] with the additional
114    ///   requested capacity allocated outside the lock and
115    /// * the lock gets reacquired,
116    /// * if the memory allocation was successful, the original [`Vec`]'s
117    ///   elements get moved into the new memory,
118    /// * the guard for the *reacquired* lock gets returned back to the caller.
119    ///
120    /// Furthermore, there are provisions to handle multiple concurrent
121    /// reservations correctly.
122    ///
123    /// # Arguments:
124    ///
125    /// * `this` - The [`Lock`](sync_types::Lock) rotecting the `SyncVec`
126    ///   instance.
127    /// * `guard` - [`Locking guard`](sync_types::Lock::Guard) for `this`. Will
128    ///   get returned back to the caller on success, **but might have been
129    ///   dropped and reacquired in the course**.
130    /// * `additional_capacity` - The additional capacity to reserve. On
131    ///   success, the underlying `Vec` is guaranteed to have storage sufficient
132    ///   to hold that many additional elements without any reallocation, as
133    ///   long as the [`Locking guard`](sync_types::Lock::Guard) is alive.
134    pub fn try_reserve<'a, L: sync_types::Lock<Self>>(
135        this: &'a L,
136        guard: L::Guard<'a>,
137        additional_capacity: usize,
138    ) -> (L::Guard<'a>, Result<(), SyncVecError>) {
139        Self::try_reserve_impl(this, guard, additional_capacity, false)
140    }
141
142    /// The implementation common to [`try_reserve()`](Self::try_reserve) and
143    /// [`try_reserve_exact()`](Self::try_reserve_exact).
144    fn try_reserve_impl<'a, L: sync_types::Lock<Self>>(
145        this: &'a L,
146        mut guard: L::Guard<'a>,
147        additional_capacity: usize,
148        exact: bool,
149    ) -> (L::Guard<'a>, Result<(), SyncVecError>) {
150        // Don't allocate under the lock. If there's enough capacity and no concurrent
151        // pending reallocations, just return. Otherwise announce
152        // the pending allocation (i.e. the additional capacity required), drop
153        // the lock, allocate, and install the reallocated Vec.
154        // Note that as per the logic of this function, the addition of v.len() and
155        // pending_reservations_additional_capacity can overflow only on misuse of this
156        // API, i.e. when either pushing outside the lock guard instance
157        // returned by this function, or when pushing more elements than have
158        // been allocated.
159        let reallocated_capacity =
160            match (guard.v.len() + guard.pending_reservations_additional_capacity).checked_add(additional_capacity) {
161                Some(reallocated_capacity) => reallocated_capacity,
162                None => return (guard, Err(SyncVecError::MemoryAllocationFailure)),
163            };
164
165        if guard.v.capacity() >= reallocated_capacity {
166            return (guard, Ok(()));
167        };
168        // Announce the pending reallocation. From now on, after releasing the lock,
169        // any subsequent concurrent reallocation will include the requested
170        // number of spare entries for us.
171        guard.pending_reservations_additional_capacity += additional_capacity;
172        drop(guard);
173
174        let mut reallocated_v = Vec::new();
175        let allocation_failed = if exact {
176            reallocated_v.try_reserve_exact(reallocated_capacity).is_err()
177        } else {
178            reallocated_v.try_reserve(reallocated_capacity).is_err()
179        };
180        if allocation_failed {
181            let mut guard = this.lock();
182            guard.pending_reservations_additional_capacity -= additional_capacity;
183            return (guard, Err(SyncVecError::MemoryAllocationFailure));
184        }
185
186        let mut guard = this.lock();
187        // Here as well, the addition of v.len() and
188        // pending_reservations_additional_capacity can overflow only upon
189        // misuse of this API.
190        if guard.v.capacity()
191            >= reallocated_capacity.min(guard.v.len() + guard.pending_reservations_additional_capacity)
192        {
193            // Someone else came in and did the allocation already, including
194            // the entries for us.
195            guard.pending_reservations_additional_capacity -= additional_capacity;
196            return (guard, Ok(()));
197        }
198
199        debug_assert!(reallocated_capacity > guard.v.len());
200        reallocated_v.append(&mut guard.v);
201        guard.v = reallocated_v;
202        guard.pending_reservations_additional_capacity -= additional_capacity;
203
204        (guard, Ok(()))
205    }
206}
207
208impl<T: marker::Send> ops::Deref for SyncVec<T> {
209    type Target = Vec<T>;
210
211    fn deref(&self) -> &Self::Target {
212        &self.v
213    }
214}
215
216impl<T: marker::Send> ops::DerefMut for SyncVec<T> {
217    fn deref_mut(&mut self) -> &mut Self::Target {
218        &mut self.v
219    }
220}
221
222impl<T: marker::Send> Default for SyncVec<T> {
223    fn default() -> Self {
224        Self::new()
225    }
226}