Skip to content

Add XArray abstraction #1019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 37 commits into
base: rust-dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
520a56a
rust: allocator: Prevents mis-aligned allocation
fbq Jun 13, 2023
3d8d9bc
rust: make `UnsafeCell` the outer type in `Opaque`
Darksonn Jun 14, 2023
7671527
rust: types: make `Opaque` be `!Unpin`
y86-dev Jun 30, 2023
0ad204c
kbuild: rust_is_available: remove -v option
masahir0y Jun 16, 2023
70a61eb
kbuild: rust_is_available: fix version check when CC has multiple arg…
ruscur Jun 16, 2023
a250bde
docs: rust: add paragraph about finding a suitable `libclang`
ojeda Jun 16, 2023
00383f7
kbuild: rust_is_available: print docs reference
ojeda Jun 16, 2023
8b2e73a
kbuild: rust_is_available: add check for `bindgen` invocation
ojeda Jun 16, 2023
eb9199d
kbuild: rust_is_available: check that environment variables are set
ojeda Jun 16, 2023
6bed841
kbuild: rust_is_available: fix confusion when a version appears in th…
ojeda Jun 16, 2023
600eb66
kbuild: rust_is_available: normalize version matching
ojeda Jun 16, 2023
6d4220b
kbuild: rust_is_available: handle failures calling `$RUSTC`/`$BINDGEN`
ojeda Jun 16, 2023
10452fc
kbuild: rust_is_available: check that output looks as expected
ojeda Jun 16, 2023
6a4e6dc
kbuild: rust_is_available: add test suite
ojeda Jun 16, 2023
f2f2787
rust: alloc: Add realloc and alloc_zeroed to the GlobalAlloc impl
fbq Jun 25, 2023
53dd54f
rust: bindgen: upgrade to 0.65.1
Shinyzenith Jun 12, 2023
02ddf5a
rust: init: make doctests compilable/testable
ojeda Jun 14, 2023
276f14d
rust: str: make doctests compilable/testable
ojeda Jun 14, 2023
c30db85
rust: sync: make doctests compilable/testable
ojeda Jun 14, 2023
4009de1
rust: types: make doctests compilable/testable
ojeda Jun 14, 2023
e9e95cd
rust: support running Rust documentation tests as KUnit ones
ojeda Jun 14, 2023
eff7a66
MAINTAINERS: add Rust KUnit files to the KUnit entry
ojeda Jun 14, 2023
72fbe4a
rust: macros: fix redefine const_name in `vtable`
cqs21 Jun 26, 2023
8e87a0d
rust: macros: add `paste!` proc macro
nbdd0121 Jun 28, 2023
7c6e564
arm64: rust: Enable Rust support for AArch64
JamieCunliffe Jun 6, 2023
522ba05
arm64: rust: Enable PAC support for Rust.
JamieCunliffe Jun 6, 2023
b1555e1
arm64: Restrict Rust support to little endian only.
JamieCunliffe Jun 6, 2023
19b33fc
rust: bindgen: update installation instructions
matthewtgilbride Jun 29, 2023
c1c510f
rust: xarray: Add an abstraction for XArray
asahilina Jun 27, 2023
91f4147
rust: xarray: add rudimentary doctest
matthewtgilbride Jun 27, 2023
6c19acb
rust: xarray: add `get_mutable` and `find_mut`
matthewtgilbride Jun 27, 2023
3016eac
rust: xarray: add reservation mechanism
asahilina Jun 27, 2023
90ddba2
Why does this cuase NULL pointer dereference?
matthewtgilbride Jul 2, 2023
702746d
Just me thrashing about - figuring out NPE
matthewtgilbride Jul 4, 2023
976067b
rust: delete `ForeignOwnable::borrow_mut`
Darksonn Jul 6, 2023
ac520c2
rust: add improved version of `ForeignOwnable::borrow_mut`
Darksonn Jul 10, 2023
642ff49
rust: xarray: figure out pin and get_scoped
matthewtgilbride Jul 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rust: add improved version of ForeignOwnable::borrow_mut
Previously, the `ForeignOwnable` trait had a method called `borrow_mut`
that was intended to provide mutable access to the inner value. However,
the method accidentally made it possible to change the address of the
object being modified, which usually isn't what we want. (And when we
want that, it can be done by calling `from_foreign` and `into_foreign`,
like how the old `borrow_mut` was implemented.)

In this patch, we introduce an alternate definition of `borrow_mut` that
solves the previous problem. Conceptually, given a pointer type `P` that
implements `ForeignOwnable`, the `borrow_mut` method gives you the same
kind of access as an `&mut P` would, except that it does not let you
change the pointer `P` itself.

This is analogous to how the existing `borrow` method provides the same
kind of access to the inner value as an `&P`.

Note that for types like `Arc`, having an `&mut Arc<T>` only gives you
immutable access to the inner `T`. This is because mutable references
assume exclusive access, but there might be other handles to the same
reference counted value, so the access isn't exclusive. The `Arc` type
implements this by making `borrow_mut` return the same type as `borrow`.

Signed-off-by: Alice Ryhl <[email protected]>
Reviewed-by: Boqun Feng <[email protected]>
  • Loading branch information
Darksonn authored and matthewtgilbride committed Jul 11, 2023
commit ac520c2166c9a64e7ea37665d9df82251852778f
25 changes: 17 additions & 8 deletions rust/kernel/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,26 +235,35 @@ impl<T: ?Sized> Arc<T> {

impl<T: 'static> ForeignOwnable for Arc<T> {
type Borrowed<'a> = ArcBorrow<'a, T>;
// Mutable access to the `Arc` does not give any extra abilities over
// immutable access.
type BorrowedMut<'a> = ArcBorrow<'a, T>;

fn into_foreign(self) -> *const core::ffi::c_void {
ManuallyDrop::new(self).ptr.as_ptr() as _
}

unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
// holds a reference count increment that is transferrable to us.
unsafe { Self::from_inner(NonNull::new_unchecked(ptr as _)) }
}

unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> {
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`.
let inner = NonNull::new(ptr as *mut ArcInner<T>).unwrap();
let inner = unsafe { NonNull::new_unchecked(ptr as *mut ArcInner<T>) };

// SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive
// for the lifetime of the returned value.
// SAFETY: The safety requirements ensure that we will not give up our
// foreign-owned refcount while the `ArcBorrow` is still live.
unsafe { ArcBorrow::new(inner) }
}

unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
// holds a reference count increment that is transferrable to us.
unsafe { Self::from_inner(NonNull::new(ptr as _).unwrap()) }
unsafe fn borrow_mut<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
// requirements for `borrow`.
unsafe { Self::borrow(ptr) }
}
}

Expand Down
87 changes: 66 additions & 21 deletions rust/kernel/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,66 +20,111 @@ use core::{
/// This trait is meant to be used in cases when Rust objects are stored in C objects and
/// eventually "freed" back to Rust.
pub trait ForeignOwnable: Sized {
/// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and
/// [`ForeignOwnable::from_foreign`].
/// Type used to immutably borrow a value that is currently foreign-owned.
type Borrowed<'a>;

/// Type used to mutably borrow a value that is currently foreign-owned.
type BorrowedMut<'a>;

/// Converts a Rust-owned object to a foreign-owned one.
///
/// The foreign representation is a pointer to void.
fn into_foreign(self) -> *const core::ffi::c_void;

/// Borrows a foreign-owned object.
/// Converts a foreign-owned object back to a Rust-owned one.
///
/// # Safety
///
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and it
/// must not be passed to `from_foreign` more than once.
///
/// [`into_foreign`]: Self::into_foreign
unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self;

/// Borrows a foreign-owned object immutably.
///
/// This method provides a way to access a foreign-owned value from Rust immutably. It provides
/// you with exactly the same abilities as an `&Self` when the value is Rust-owned.
///
/// # Safety
///
/// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for
/// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet.
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
/// the lifetime 'a.
///
/// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>;

/// Converts a foreign-owned object back to a Rust-owned one.
/// Borrows a foreign-owned object mutably.
///
/// This method provides a way to access a foreign-owned value from Rust mutably. It provides
/// you with exactly the same abilities as an `&mut Self` when the value is Rust-owned, except
/// that this method does not let you swap the foreign-owned object for another. (That is, it
/// does not let you change the address of the void pointer that the foreign code is storing.)
///
/// Note that for types like [`Arc`], an `&mut Arc<T>` only gives you immutable access to the
/// inner value, so this method also only provides immutable access in that case.
///
/// In the case of `Box<T>`, this method gives you the ability to modify the inner `T`, but it
/// does not let you change the box itself. That is, you cannot change which allocation the box
/// points at.
///
/// # Safety
///
/// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for
/// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet.
/// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for
/// this object must have been dropped.
unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self;
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
/// the lifetime 'a.
///
/// The lifetime 'a must not overlap with the lifetime of any other call to [`borrow`] or
/// `borrow_mut` on the same object.
///
/// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign
/// [`borrow`]: Self::borrow
/// [`Arc`]: crate::sync::Arc
unsafe fn borrow_mut<'a>(ptr: *const core::ffi::c_void) -> Self::BorrowedMut<'a>;
}

impl<T: 'static> ForeignOwnable for Box<T> {
type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T;

fn into_foreign(self) -> *const core::ffi::c_void {
Box::into_raw(self) as _
}

unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
// the lifetime of the returned value.
unsafe { &*ptr.cast() }
}

unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
unsafe { Box::from_raw(ptr as _) }
}

unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
// SAFETY: The safety requirements of this method ensure that the object remains alive and
// immutable for the duration of 'a.
unsafe { &*ptr.cast() }
}

unsafe fn borrow_mut<'a>(ptr: *const core::ffi::c_void) -> &'a mut T {
// SAFETY: The safety requirements of this method ensure that the pointer is valid and that
// nothing else will access the value for the duration of 'a.
unsafe { &mut *ptr.cast_mut().cast() }
}
}

impl ForeignOwnable for () {
type Borrowed<'a> = ();
type BorrowedMut<'a> = ();

fn into_foreign(self) -> *const core::ffi::c_void {
core::ptr::NonNull::dangling().as_ptr()
}

unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {}

unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {}

unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {}
unsafe fn borrow_mut<'a>(_: *const core::ffi::c_void) -> Self::BorrowedMut<'a> {}
}

/// Runs a cleanup function/closure when dropped.
Expand Down