Skip to content

Commit 0670bbc

Browse files
hoshinolinajannau
authored andcommitted
rust: kernel: xarray: Implement XArray::find()
Signed-off-by: Asahi Lina <lina@asahilina.net> Co-developed-by: Janne Grunau <j@jannau.net> Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 51cc3e6 commit 0670bbc

1 file changed

Lines changed: 62 additions & 1 deletion

File tree

rust/kernel/xarray.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::{
88
alloc,
99
prelude::*,
10-
types::{ForeignOwnable, NotThreadSafe, Opaque},
10+
types::{ForeignOwnable, NotThreadSafe, Opaque, ScopeGuard},
1111
};
1212
use core::{
1313
fmt, iter,
@@ -131,6 +131,36 @@ impl<T: ForeignOwnable> XArray<T> {
131131
.map_while(|ptr| NonNull::new(ptr.cast()))
132132
}
133133

134+
/// Looks up and returns a reference to the lowest entry in the array between index and max,
135+
/// returning a tuple of its index and a `Guard` if one exists.
136+
///
137+
/// This guard blocks all other actions on the `XArray`. Callers are expected to drop the
138+
/// `Guard` eagerly to avoid blocking other users, such as by taking a clone of the value.
139+
pub fn find(&self, index: usize, max: usize) -> Option<(usize, ValueGuard<'_, T>)> {
140+
let mut index: usize = index;
141+
142+
// SAFETY: `self.xa` is always valid by the type invariant.
143+
unsafe { bindings::xa_lock(self.xa.get()) };
144+
145+
// SAFETY: `self.xa` is always valid by the type invariant.
146+
let guard = ScopeGuard::new(|| unsafe { bindings::xa_unlock(self.xa.get()) });
147+
148+
// SAFETY: `self.xa` is always valid by the type invariant.
149+
let p = unsafe { bindings::xa_find(self.xa.get(), &mut index, max, bindings::XA_PRESENT) };
150+
151+
NonNull::new(p as *mut T).map(|ptr| {
152+
guard.dismiss();
153+
(
154+
index,
155+
ValueGuard {
156+
xa: self,
157+
ptr,
158+
_not_send: NotThreadSafe,
159+
},
160+
)
161+
})
162+
}
163+
134164
fn with_guard<F, U>(&self, guard: Option<&mut Guard<'_, T>>, f: F) -> U
135165
where
136166
F: FnOnce(&mut Guard<'_, T>) -> U,
@@ -187,6 +217,37 @@ impl<T: ForeignOwnable> Drop for Guard<'_, T> {
187217
}
188218
}
189219

220+
/// A lock guard.
221+
///
222+
/// The lock is unlocked when the guard goes out of scope.
223+
#[must_use = "the lock unlocks immediately when the guard is unused"]
224+
pub struct ValueGuard<'a, T: ForeignOwnable> {
225+
xa: &'a XArray<T>,
226+
ptr: NonNull<T>,
227+
_not_send: NotThreadSafe,
228+
}
229+
230+
impl<'a, T: ForeignOwnable> ValueGuard<'a, T> {
231+
/// Borrow the underlying value wrapped by the `Guard`.
232+
///
233+
/// Returns a `T::Borrowed` type for the owned `ForeignOwnable` type.
234+
pub fn borrow(&self) -> T::Borrowed<'_> {
235+
// SAFETY: The value is owned by the `XArray`, the lifetime it is borrowed for must not
236+
// outlive the `XArray` itself, nor the Guard that holds the lock ensuring the value
237+
// remains in the `XArray`.
238+
unsafe { T::borrow(self.ptr.as_ptr() as _) }
239+
}
240+
}
241+
242+
impl<T: ForeignOwnable> Drop for ValueGuard<'_, T> {
243+
fn drop(&mut self) {
244+
// SAFETY:
245+
// - `self.xa.xa` is always valid by the type invariant.
246+
// - The caller holds the lock, so it is safe to unlock it.
247+
unsafe { bindings::xa_unlock(self.xa.xa.get()) };
248+
}
249+
}
250+
190251
/// The error returned by [`store`](Guard::store).
191252
///
192253
/// Contains the underlying error and the value that was not stored.

0 commit comments

Comments
 (0)