"Tamir Duberstein" <tamird@xxxxxxxxx> writes: > Add `Guard::{insert,reserve}` and `Guard::{insert,reserve}_limit`, which > are akin to `__xa_{alloc,insert}` in C. > > Note that unlike `xa_reserve` which only ensures that memory is > allocated, the semantics of `Reservation` are stricter and require > precise management of the reservation. Indices which have been reserved > can still be overwritten with `Guard::store`, which allows for C-like > semantics if desired. > > `__xa_cmpxchg_raw` is exported to facilitate the semantics described > above. > > Tested-by: Janne Grunau <j@xxxxxxxxxx> > Reviewed-by: Janne Grunau <j@xxxxxxxxxx> > Signed-off-by: Tamir Duberstein <tamird@xxxxxxxxx> <cut> > + /// Stores an element somewhere in the given range of indices. > + /// > + /// On success, takes ownership of `ptr`. > + /// > + /// On failure, ownership returns to the caller. > + /// > + /// # Safety > + /// > + /// `ptr` must be `NULL` or have come from a previous call to `T::into_foreign`. > + unsafe fn alloc( The naming of this method in C is confusing. Could we call it insert_limit_raw on the Rust side? Even though this is private, I think we should also document that the effect of inserting NULL is to reserve the entry. > + &mut self, > + limit: impl ops::RangeBounds<u32>, > + ptr: *mut T::PointedTo, > + gfp: alloc::Flags, > + ) -> Result<usize> { > + // NB: `xa_limit::{max,min}` are inclusive. > + let limit = bindings::xa_limit { > + max: match limit.end_bound() { > + ops::Bound::Included(&end) => end, > + ops::Bound::Excluded(&end) => end - 1, > + ops::Bound::Unbounded => u32::MAX, > + }, > + min: match limit.start_bound() { > + ops::Bound::Included(&start) => start, > + ops::Bound::Excluded(&start) => start + 1, > + ops::Bound::Unbounded => 0, > + }, > + }; > + > + let mut index = u32::MAX; > + > + // SAFETY: > + // - `self.xa` is always valid by the type invariant. > + // - `self.xa` was initialized with `XA_FLAGS_ALLOC` or `XA_FLAGS_ALLOC1`. > + // > + // INVARIANT: `ptr` is either `NULL` or came from `T::into_foreign`. > + match unsafe { > + bindings::__xa_alloc( > + self.xa.xa.get(), > + &mut index, > + ptr.cast(), > + limit, > + gfp.as_raw(), > + ) > + } { > + 0 => Ok(to_usize(index)), > + errno => Err(Error::from_errno(errno)), > + } > + } > + > + /// Allocates an entry somewhere in the array. Should we rephrase this to match `alloc`? Stores an entry somewhere in the given range of indices. <cut> > +impl<T: ForeignOwnable> Reservation<'_, T> { > + /// Returns the index of the reservation. > + pub fn index(&self) -> usize { > + self.index > + } > + > + /// Replaces the reserved entry with the given entry. > + /// > + /// # Safety > + /// > + /// `ptr` must be `NULL` or have come from a previous call to `T::into_foreign`. We should document the effect of replacing with NULL. Best regards, Andreas Hindborg