All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Andreas Hindborg (Samsung)" <nmi@metaspace.dk>
To: Alice Ryhl <aliceryhl@google.com>
Cc: rust-for-linux@vger.kernel.org, "Miguel Ojeda" <ojeda@kernel.org>,
	"Wedson Almeida Filho" <wedsonaf@gmail.com>,
	"Tejun Heo" <tj@kernel.org>,
	"Lai Jiangshan" <jiangshanlai@gmail.com>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	linux-kernel@vger.kernel.org, patches@lists.linux.dev
Subject: Re: [PATCH v2 6/8] rust: workqueue: implement `WorkItemPointer` for pointer types
Date: Fri, 02 Jun 2023 16:42:44 +0200	[thread overview]
Message-ID: <87fs7a0vtd.fsf@metaspace.dk> (raw)
In-Reply-To: <20230601134946.3887870-7-aliceryhl@google.com>


Alice Ryhl <aliceryhl@google.com> writes:

> This implements the `WorkItemPointer` trait for the pointer types that
> you are likely to use the workqueue with. The `Arc` type is for
> reference counted objects, and the `Pin<Box<T>>` type is for objects
> where the caller has exclusive ownership of the object.
>
> Co-developed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>

Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>

> ---
>  rust/kernel/workqueue.rs | 97 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 96 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
> index dbf0aab29a85..f06a2f036d8b 100644
> --- a/rust/kernel/workqueue.rs
> +++ b/rust/kernel/workqueue.rs
> @@ -28,8 +28,10 @@
>  //!
>  //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
>  
> -use crate::{bindings, prelude::*, types::Opaque};
> +use crate::{bindings, prelude::*, sync::Arc, types::Opaque};
> +use alloc::boxed::Box;
>  use core::marker::{PhantomData, PhantomPinned};
> +use core::pin::Pin;
>  
>  /// A kernel work queue.
>  ///
> @@ -323,6 +325,99 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_typ
>      )*};
>  }
>  
> +unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T>
> +where
> +    T: WorkItem<ID, Pointer = Self>,
> +    T: HasWork<T, ID>,
> +{
> +    unsafe extern "C" fn run(ptr: *mut bindings::work_struct) {
> +        // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`.
> +        let ptr = ptr as *mut Work<T, ID>;
> +        // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
> +        let ptr = unsafe { T::work_container_of(ptr) };
> +        // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
> +        let arc = unsafe { Arc::from_raw(ptr) };
> +
> +        T::run(arc)
> +    }
> +}
> +
> +unsafe impl<T, const ID: u64> RawWorkItem<ID> for Arc<T>
> +where
> +    T: WorkItem<ID, Pointer = Self>,
> +    T: HasWork<T, ID>,
> +{
> +    type EnqueueOutput = Result<(), Self>;
> +
> +    unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
> +    where
> +        F: FnOnce(*mut bindings::work_struct) -> bool,
> +    {
> +        // Casting between const and mut is not a problem as long as the pointer is a raw pointer.
> +        let ptr = Arc::into_raw(self) as *mut T;
> +
> +        // SAFETY: Pointers into an `Arc` point at a valid value.
> +        let work_ptr = unsafe { T::raw_get_work(ptr) };
> +        // SAFETY: `raw_get_work` returns a pointer to a valid value.
> +        let work_ptr = unsafe { Work::raw_get(work_ptr) };
> +
> +        if queue_work_on(work_ptr) {
> +            Ok(())
> +        } else {
> +            // SAFETY: The work queue has not taken ownership of the pointer.
> +            Err(unsafe { Arc::from_raw(ptr) })
> +        }
> +    }
> +}
> +
> +unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>>
> +where
> +    T: WorkItem<ID, Pointer = Self>,
> +    T: HasWork<T, ID>,
> +{
> +    unsafe extern "C" fn run(ptr: *mut bindings::work_struct) {
> +        // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`.
> +        let ptr = ptr as *mut Work<T, ID>;
> +        // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
> +        let ptr = unsafe { T::work_container_of(ptr) };
> +        // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
> +        let boxed = unsafe { Box::from_raw(ptr) };
> +        // SAFETY: The box was already pinned when it was enqueued.
> +        let pinned = unsafe { Pin::new_unchecked(boxed) };
> +
> +        T::run(pinned)
> +    }
> +}
> +
> +unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<Box<T>>
> +where
> +    T: WorkItem<ID, Pointer = Self>,
> +    T: HasWork<T, ID>,
> +{
> +    type EnqueueOutput = ();
> +
> +    unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
> +    where
> +        F: FnOnce(*mut bindings::work_struct) -> bool,
> +    {
> +        // SAFETY: We're not going to move `self` or any of its fields, so its okay to temporarily
> +        // remove the `Pin` wrapper.
> +        let boxed = unsafe { Pin::into_inner_unchecked(self) };
> +        let ptr = Box::into_raw(boxed);
> +
> +        // SAFETY: Pointers into a `Box` point at a valid value.
> +        let work_ptr = unsafe { T::raw_get_work(ptr) };
> +        // SAFETY: `raw_get_work` returns a pointer to a valid value.
> +        let work_ptr = unsafe { Work::raw_get(work_ptr) };
> +
> +        if !queue_work_on(work_ptr) {
> +            // SAFETY: This method requires exclusive ownership of the box, so it cannot be in a
> +            // workqueue.
> +            unsafe { ::core::hint::unreachable_unchecked() }
> +        }
> +    }
> +}
> +
>  /// Returns the system work queue (`system_wq`).
>  ///
>  /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are


  parent reply	other threads:[~2023-06-02 14:42 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-01 13:49 [PATCH v2 0/8] rust: workqueue: add bindings for the workqueue Alice Ryhl
2023-06-01 13:49 ` [PATCH v2 1/8] rust: workqueue: add low-level workqueue bindings Alice Ryhl
2023-06-01 14:29   ` Martin Rodriguez Reboredo
2023-06-02 14:39   ` Andreas Hindborg (Samsung)
2023-06-06 23:36   ` Boqun Feng
2023-06-07 15:18     ` Alice Ryhl
2023-06-11 15:45   ` Benno Lossin
2023-06-01 13:49 ` [PATCH v2 2/8] rust: add offset_of! macro Alice Ryhl
2023-06-01 17:17   ` Gary Guo
2023-06-02 10:33   ` Andreas Hindborg (Samsung)
2023-06-07 15:15     ` Alice Ryhl
2023-06-11 15:47   ` Benno Lossin
2023-06-01 13:49 ` [PATCH v2 3/8] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
2023-06-01 17:26   ` Gary Guo
2023-06-02 10:51   ` Andreas Hindborg (Samsung)
2023-06-05 14:31     ` Gary Guo
2023-06-05 14:49       ` Andreas Hindborg (Samsung)
2023-06-05 15:00       ` Boqun Feng
2023-06-05 15:20         ` Boqun Feng
2023-06-05 18:34         ` Andreas Hindborg (Samsung)
2023-06-11 15:48   ` Benno Lossin
2023-06-01 13:49 ` [PATCH v2 4/8] rust: workqueue: define built-in queues Alice Ryhl
2023-06-01 17:30   ` Gary Guo
2023-06-01 17:52     ` Martin Rodriguez Reboredo
2023-06-02  8:32     ` Alice Ryhl
2023-06-02 14:46   ` Andreas Hindborg (Samsung)
2023-06-11 15:49   ` Benno Lossin
2023-06-01 13:49 ` [PATCH v2 5/8] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
2023-06-01 14:50   ` Martin Rodriguez Reboredo
2023-06-01 18:44   ` Boqun Feng
2023-06-02  8:38     ` Alice Ryhl
2023-06-02 16:32       ` Boqun Feng
2023-06-01 21:09   ` Boqun Feng
2023-06-02  9:37     ` Alice Ryhl
2023-06-02 14:41   ` Andreas Hindborg (Samsung)
2023-06-11 15:59   ` Benno Lossin
2023-06-27  8:42     ` Alice Ryhl
2023-06-01 13:49 ` [PATCH v2 6/8] rust: workqueue: implement `WorkItemPointer` for pointer types Alice Ryhl
2023-06-01 14:51   ` Martin Rodriguez Reboredo
2023-06-02 14:42   ` Andreas Hindborg (Samsung) [this message]
2023-06-11 16:01   ` Benno Lossin
2023-06-01 13:49 ` [PATCH v2 7/8] rust: workqueue: add `try_spawn` helper method Alice Ryhl
2023-06-01 14:53   ` Martin Rodriguez Reboredo
2023-06-02 14:43   ` Andreas Hindborg (Samsung)
2023-06-11 16:10   ` Benno Lossin
2023-06-01 13:49 ` [PATCH v2 8/8] rust: workqueue: add examples Alice Ryhl
2023-06-01 14:58   ` Martin Rodriguez Reboredo
2023-06-01 17:32   ` Gary Guo
2023-06-02  9:39     ` Alice Ryhl
2023-06-02 14:44   ` Andreas Hindborg (Samsung)
2023-06-02 14:48   ` Andreas Hindborg (Samsung)
2023-06-11 16:15   ` Benno Lossin
2023-06-27  8:38     ` Alice Ryhl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87fs7a0vtd.fsf@metaspace.dk \
    --to=nmi@metaspace.dk \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=gary@garyguo.net \
    --cc=jiangshanlai@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=patches@lists.linux.dev \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tj@kernel.org \
    --cc=wedsonaf@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.