Re: [PATCH v2] rust: xarray: Add an abstraction for XArray

From: Asahi Lina
Date: Thu Mar 23 2023 - 12:30:45 EST



Why do I always notice mistakes after sending the patch... this is
missing the comment I intended to add because I edited the file in the
wrong git checkout. Sorry!

The intended comment is below, I'll roll it into v3 when I make the Error API change.

On 24/03/2023 01.23, Asahi Lina wrote:
The XArray is an abstract data type which behaves like a very large
array of pointers. Add a Rust abstraction for this data type.

The initial implementation uses explicit locking on get operations and
returns a guard which blocks mutation, ensuring that the referenced
object remains alive. To avoid excessive serialization, users are
expected to use an inner type that can be efficiently cloned (such as
Arc<T>), and eagerly clone and drop the guard to unblock other users
after a lookup.

Future variants may support using RCU instead to avoid mutex locking.

This abstraction also introduces a reservation mechanism, which can be
used by alloc-capable XArrays to reserve a free slot without immediately
filling it, and then do so at a later time. If the reservation is
dropped without being filled, the slot is freed again for other users,
which eliminates the need for explicit cleanup code.

Signed-off-by: Asahi Lina <lina@xxxxxxxxxxxxx>
[...]
+impl<T: ForeignOwnable> Drop for XArray<T> {
+ fn drop(&mut self) {
+ // SAFETY: `self.xa` is valid by the type invariant, and as we have the only reference to
+ // the `XArray` we can safely iterate its contents and drop everything.
+ unsafe {
+ let mut index: core::ffi::c_ulong = 0;
+ let mut entry = bindings::xa_find(
+ self.xa.get(),
+ &mut index,
+ core::ffi::c_ulong::MAX,
+ bindings::BINDINGS_XA_PRESENT,
+ );
+ while !entry.is_null() {
+ T::from_foreign(entry);
+ entry = bindings::xa_find_after(
+ self.xa.get(),
+ &mut index,
+ core::ffi::c_ulong::MAX,
+ bindings::BINDINGS_XA_PRESENT,
+ );
+ }
+

Add for v3:
+ // Locked locks are not safe to drop. Normally we would want to try_lock()/unlock() here
+ // for safety or something similar, but in this case xa_destroy() is guaranteed to
+ // acquire the lock anyway. This will deadlock if a lock guard was improperly dropped,
+ // but that is not UB, so it's sufficient for soundness purposes.

+ bindings::xa_destroy(self.xa.get());
+ }
+ }
+}
+
+// SAFETY: XArray is thread-safe and all mutation operations are internally locked.
+unsafe impl<T: Send + ForeignOwnable> Send for XArray<T> {}
+unsafe impl<T: Sync + ForeignOwnable> Sync for XArray<T> {}

---
base-commit: 3ef2e9730ba4bb914dd8654ae34aef3f486c8c58
change-id: 20230224-rust-xarray-f503f9e5455e

Thank you,
~~ Lina



~~ Lina