[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAH5fLggchaAzcRK=i=zRm7hTg6qX0yGBAyAHcO45rG-oEh-AMQ@mail.gmail.com>
Date: Wed, 14 Aug 2024 10:42:28 +0200
From: Alice Ryhl <aliceryhl@...gle.com>
To: Danilo Krummrich <dakr@...nel.org>
Cc: ojeda@...nel.org, alex.gaynor@...il.com, wedsonaf@...il.com,
boqun.feng@...il.com, gary@...yguo.net, bjorn3_gh@...tonmail.com,
benno.lossin@...ton.me, a.hindborg@...sung.com, akpm@...ux-foundation.org,
daniel.almeida@...labora.com, faith.ekstrand@...labora.com,
boris.brezillon@...labora.com, lina@...hilina.net, mcanal@...lia.com,
zhiw@...dia.com, cjia@...dia.com, jhubbard@...dia.com, airlied@...hat.com,
ajanulgu@...hat.com, lyude@...hat.com, linux-kernel@...r.kernel.org,
rust-for-linux@...r.kernel.org, linux-mm@...ck.org
Subject: Re: [PATCH v5 13/26] rust: alloc: implement kernel `Vec` type
On Mon, Aug 12, 2024 at 8:25 PM Danilo Krummrich <dakr@...nel.org> wrote:
>
> `Vec` provides a contiguous growable array type (such as `Vec`) with
> contents allocated with the kernel's allocators (e.g. `Kmalloc`,
> `Vmalloc` or `KVmalloc`).
>
> In contrast to Rust's `Vec` type, the kernel `Vec` type considers the
> kernel's GFP flags for all appropriate functions, always reports
> allocation failures through `Result<_, AllocError>` and remains
> independent from unstable features.
>
> Signed-off-by: Danilo Krummrich <dakr@...nel.org>
> [...]
> +impl<T, A, const N: usize> Box<[T; N], A>
> +where
> + A: Allocator,
> +{
> + /// Convert a `Box<[T, N], A>` to a `Vec<T, A>`.
> + pub fn into_vec(b: Self) -> Vec<T, A> {
Nit: I would probably make this a From impl.
> +#[macro_export]
> +macro_rules! kvec {
> + () => (
> + {
> + $crate::alloc::KVec::new()
> + }
> + );
> + ($elem:expr; $n:expr) => (
> + {
> + $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL)
> + }
> + );
> + ($($x:expr),+ $(,)?) => (
> + {
> + match $crate::alloc::KBox::new([$($x),+], GFP_KERNEL) {
> + Ok(b) => Ok($crate::alloc::KBox::into_vec(b)),
> + Err(e) => Err(e),
Hmm. This currently generates code that:
1. Creates the array.
2. Allocates the memory.
3. Moves the array into the box.
Whereas the stdlib macro swaps step 1 and 2. You can do the same by
utilizing new_uninit. A sketch:
match KBox::<[_; _]>::new_uninit(GFP_KERNEL) {
Ok(b) => Ok(KVec::from(KBox::write(b, [$($x),+]))),
Err(e) => Err(e),
}
> +// SAFETY: `Vec` is `Send` if `T` is `Send` because the data referenced by `self.ptr` is unaliased.
> +unsafe impl<T, A> Send for Vec<T, A>
> +where
> + T: Send,
> + A: Allocator,
> +{
> +}
> +
> +// SAFETY: `Vec` is `Sync` if `T` is `Sync` because the data referenced by `self.ptr` is unaliased.
> +unsafe impl<T, A> Sync for Vec<T, A>
> +where
> + T: Send,
> + A: Allocator,
Same comment as Box. Ditto about "unaliased". Needs `T: Sync` instead.
> +impl<T: Clone, A: Allocator> Vec<T, A> {
> + /// Extend the vector by `n` clones of value.
> + pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> {
> + self.reserve(n, flags)?;
> +
> + let spare = self.spare_capacity_mut();
> +
> + for item in spare.iter_mut().take(n - 1) {
You need to handle `n == 0` here.
Alice
Powered by blists - more mailing lists