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}