From: Alice Ryhl <aliceryhl@google.com>
To: k.shelekhin@ftml.net
Cc: alex.gaynor@gmail.com, aliceryhl@google.com,
benno.lossin@proton.me, bjorn3_gh@protonmail.com,
boqun.feng@gmail.com, gary@garyguo.net, jiangshanlai@gmail.com,
linux-kernel@vger.kernel.org, nmi@metaspace.dk,
ojeda@kernel.org, patches@lists.linux.dev,
rust-for-linux@vger.kernel.org, tj@kernel.org,
wedsonaf@gmail.com, yakoyoku@gmail.com
Subject: Re: [PATCH v4 7/7] rust: workqueue: add examples
Date: Tue, 3 Oct 2023 22:29:47 +0000 [thread overview]
Message-ID: <20231003222947.374039-1-aliceryhl@google.com> (raw)
In-Reply-To: <CVZ2KU4KK5YH.2HVL1F6X93YLL@pogg>
On Tue, Oct 3, 2023 at 10:13PM Konstantin Shelekhin <k.shelekhin@ftml.net> wrote:
> +//! #[pin_data]
> +//! struct MyStruct {
> +//! value: i32,
> +//! #[pin]
> +//! work: Work<MyStruct>,
> +//! }
> +//!
> +//! impl_has_work! {
> +//! impl HasWork<Self> for MyStruct { self.work }
> +//! }
> +//!
> +//! impl MyStruct {
> +//! fn new(value: i32) -> Result<Arc<Self>> {
> +//! Arc::pin_init(pin_init!(MyStruct {
> +//! value,
> +//! work <- new_work!("MyStruct::work"),
> +//! }))
> +//! }
> +//! }
> +//!
> +//! impl WorkItem for MyStruct {
> +//! type Pointer = Arc<MyStruct>;
> +//!
> +//! fn run(this: Arc<MyStruct>) {
> +//! pr_info!("The value is: {}", this.value);
> +//! }
> +//! }
> +//!
> +//! /// This method will enqueue the struct for execution on the system workqueue, where its value
> +//! /// will be printed.
> +//! fn print_later(val: Arc<MyStruct>) {
> +//! let _ = workqueue::system().enqueue(val);
> +//! }
>
> I understand that this is highly opionated, but is it possible to make
> the initialization less verbose?
The short answer is yes. There are safe alternatives that are much less
verbose. Unfortunately, those alternatives give up some of the features
that this design has. Specifically, they give up the feature that allows
you to embed the work_struct inside custom structs. I need to be able to
embed the work_struct inside of custom structs, so I did not go that
route.
There are also some parts of this (mainly `impl_has_work!`) that I am
unhappy with. I would be happy to see a solution that doesn't need it,
but I couldn't figure out how to avoid it.
> Because the C version looks much, much cleaner and easier to grasp:
>
> struct my_struct {
> i32 value;
> struct work_struct work;
> };
>
> void log_value(struct work_struct *work)
> {
> struct my_struct *s = container_of(work, struct my_struct, work);
> pr_info("The value is: %d\n", s->value);
> }
>
> void print_later(struct my_struct &s)
> {
> INIT_WORK(&s->work, log_value);
> schedule_work(&s->work);
> }
Although I think that a part of this is just whether you are familiar
with Rust syntax, there is definitely some truth to this. Your code is a
lot closer to the machine code of what actually happens here. Perhaps it
would be interesting to see what you get if you just unsafely do exactly
the same thing in Rust? It would look something like this:
struct MyStruct {
value: i32,
work: bindings::work_struct,
}
unsafe fn log_value(work: *mut bindings::work_struct) {
unsafe {
let s = container_of!(work, MyStruct, work);
pr_info!("The value is: {}", (*s).value);
}
}
unsafe fn print_later(s: *mut bindings::work_struct) {
unsafe {
bindings::INIT_WORK(&mut (*s).work, log_value);
bindings::schedule_work(&mut (*s).work);
}
}
(I didn't try to compile this.)
The problem with this approach is that it uses unsafe in driver code,
but the goal behind Rust abstractions is to isolate all of the related
unsafe code. The idea being that drivers using the workqueue do not need
any unsafe code to use it. This means that, assuming these workqueue
abstractions are correct, no driver can accidentally cause memory
unsafety by using the workqueue wrong.
The main difficult part of making this happen is the container_of
operation. We need to somehow verify *at compile time* that the
container_of in log_value really is given a pointer to the work field of
a MyStruct. Other than the things that are just how Rust looks, most of
the verbosity is necessary to make this compile-time check possible.
Another thing it does is handle proper transfer of ownership. In my
original example, MyStruct is reference counted (due to the use of Arc),
so the workqueue passes ownership of one refcount to the workqueue,
which eventually passes the refcount to run. When `this` goes out of
scope at the end of `run`, the refcount is decremented and the struct is
freed if the refcount dropped to zero.
If you wanted to just have exclusive ownership of my_struct, you could
do that by using Box instead of Arc. In either case, the ownership is
correctly passed to run, and you cannot accidentally forget to free it
at the end of log_value.
So, ultimately there's a tradeoff here. The code corresponds less
directly to what the machine code will be. On the other hand, it will be
*more* difficult to use incorrectly since incorrect uses will usually
result in compilation errors. The claim of Rust is that this tradeoff is
worth it.
Alice
next prev parent reply other threads:[~2023-10-03 22:29 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-28 10:48 [PATCH v4 0/7] rust: workqueue: add bindings for the workqueue Alice Ryhl
2023-08-28 10:48 ` [PATCH v4 1/7] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
2023-08-28 10:48 ` [PATCH v4 2/7] rust: workqueue: add low-level workqueue bindings Alice Ryhl
2023-08-28 10:48 ` [PATCH v4 3/7] rust: workqueue: define built-in queues Alice Ryhl
2023-08-28 10:48 ` [PATCH v4 4/7] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
[not found] ` <CGME20230828112151eucas1p2371f4cf778e6265e8ac5baf8ea91be4d@eucas1p2.samsung.com>
2023-08-28 11:21 ` Andreas Hindborg
2023-09-04 0:29 ` Martin Rodriguez Reboredo
2023-09-05 10:07 ` Benno Lossin
2023-09-06 9:56 ` Alice Ryhl
2023-09-26 10:01 ` Alice Ryhl
2023-09-23 2:56 ` Gary Guo
2023-08-28 10:48 ` [PATCH v4 5/7] rust: workqueue: implement `WorkItemPointer` for pointer types Alice Ryhl
2023-08-28 10:48 ` [PATCH v4 6/7] rust: workqueue: add `try_spawn` helper method Alice Ryhl
2023-08-28 10:48 ` [PATCH v4 7/7] rust: workqueue: add examples Alice Ryhl
2023-10-03 20:13 ` Konstantin Shelekhin
2023-10-03 22:29 ` Alice Ryhl [this message]
2023-10-04 11:06 ` Konstantin Shelekhin
2023-10-04 14:38 ` Boqun Feng
2023-10-04 14:56 ` Konstantin Shelekhin
2023-10-04 15:49 ` Andreas Hindborg (Samsung)
2023-10-05 6:32 ` Trevor Gross
2023-09-12 5:14 ` [PATCH v4 0/7] rust: workqueue: add bindings for the workqueue Boqun Feng
2023-09-25 19:49 ` Tejun Heo
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=20231003222947.374039-1-aliceryhl@google.com \
--to=aliceryhl@google.com \
--cc=alex.gaynor@gmail.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=k.shelekhin@ftml.net \
--cc=linux-kernel@vger.kernel.org \
--cc=nmi@metaspace.dk \
--cc=ojeda@kernel.org \
--cc=patches@lists.linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=tj@kernel.org \
--cc=wedsonaf@gmail.com \
--cc=yakoyoku@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).