From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Benno Lossin" <benno.lossin@proton.me>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
"Frederic Weisbecker" <frederic@kernel.org>,
"Thomas Gleixner" <tglx@linutronix.de>,
"Danilo Krummrich" <dakr@kernel.org>,
"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>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Lyude Paul" <lyude@redhat.com>,
"Guangbo Cui" <2407018371@qq.com>,
"Dirk Behme" <dirk.behme@gmail.com>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@gmail.com>,
"Markus Elfring" <Markus.Elfring@web.de>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v10 10/13] rust: hrtimer: implement `HrTimerPointer` for `Pin<Box<T>>`
Date: Fri, 07 Mar 2025 15:01:51 +0100 [thread overview]
Message-ID: <87bjud3po0.fsf@kernel.org> (raw)
In-Reply-To: <D8A2DAP4JOOK.PC50NH7JGIM2@proton.me> (Benno Lossin's message of "Fri, 07 Mar 2025 13:21:44 +0000")
"Benno Lossin" <benno.lossin@proton.me> writes:
> On Fri Mar 7, 2025 at 11:11 AM CET, Andreas Hindborg wrote:
>> Allow `Pin<Box<T>>` to be the target of a timer callback.
>>
>> Acked-by: Frederic Weisbecker <frederic@kernel.org>
>> Reviewed-by: Lyude Paul <lyude@redhat.com>
>> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
>> ---
>> rust/kernel/time/hrtimer.rs | 3 ++
>> rust/kernel/time/hrtimer/tbox.rs | 109 +++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 112 insertions(+)
>>
>> diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
>> index d2791fd624b7..991d37b0524a 100644
>> --- a/rust/kernel/time/hrtimer.rs
>> +++ b/rust/kernel/time/hrtimer.rs
>> @@ -443,3 +443,6 @@ unsafe fn timer_container_of(ptr: *mut $crate::time::hrtimer::HrTimer<$timer_typ
>> pub use pin::PinHrTimerHandle;
>> mod pin_mut;
>> pub use pin_mut::PinMutHrTimerHandle;
>> +// `box` is a reserved keyword, so prefix with `t` for timer
>> +mod tbox;
>> +pub use tbox::BoxHrTimerHandle;
>> diff --git a/rust/kernel/time/hrtimer/tbox.rs b/rust/kernel/time/hrtimer/tbox.rs
>> new file mode 100644
>> index 000000000000..a3b2ed849050
>> --- /dev/null
>> +++ b/rust/kernel/time/hrtimer/tbox.rs
>> @@ -0,0 +1,109 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +use super::HasHrTimer;
>> +use super::HrTimer;
>> +use super::HrTimerCallback;
>> +use super::HrTimerHandle;
>> +use super::HrTimerPointer;
>> +use super::RawHrTimerCallback;
>> +use crate::prelude::*;
>> +use crate::time::Ktime;
>> +use core::mem::ManuallyDrop;
>> +use core::ptr::NonNull;
>> +
>> +/// A handle for a [`Box<HasHrTimer<T>>`] returned by a call to
>> +/// [`HrTimerPointer::start`].
>> +pub struct BoxHrTimerHandle<T, A>
>
> Should this type implement `Send` and `Sync` depending on `T`?
Yes. In practice `T` will always be `Send` and `Sync` because of bounds
on other traits.
I don't think we have to require `T: Sync`, because the handle does not ever
create shared references to the underlying `T`?
>
>> +where
>> + T: HasHrTimer<T>,
>> + A: crate::alloc::Allocator,
>> +{
>> + pub(crate) inner: NonNull<T>,
>> + _p: core::marker::PhantomData<A>,
>> +}
>> +
>> +// SAFETY: We implement drop below, and we cancel the timer in the drop
>> +// implementation.
>> +unsafe impl<T, A> HrTimerHandle for BoxHrTimerHandle<T, A>
>> +where
>> + T: HasHrTimer<T>,
>> + A: crate::alloc::Allocator,
>> +{
>> + fn cancel(&mut self) -> bool {
>> + // SAFETY: As we obtained `self.inner` from a valid reference when we
>> + // created `self`, it must point to a valid `T`.
>> + let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self.inner.as_ptr()) };
>> +
>> + // SAFETY: As `timer_ptr` points into `T` and `T` is valid, `timer_ptr`
>> + // must point to a valid `HrTimer` instance.
>> + unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
>> + }
>> +}
>> +
>> +impl<T, A> Drop for BoxHrTimerHandle<T, A>
>> +where
>> + T: HasHrTimer<T>,
>> + A: crate::alloc::Allocator,
>> +{
>> + fn drop(&mut self) {
>> + self.cancel();
>> + // SAFETY: `self.inner` came from a `Box::into_raw` call
>
> Please add this as an invariant to `Self`.
OK.
>
>> + drop(unsafe { Box::<T, A>::from_raw(self.inner.as_ptr()) })
>> + }
>> +}
>> +
>> +impl<T, A> HrTimerPointer for Pin<Box<T, A>>
>> +where
>> + T: 'static,
>> + T: Send + Sync,
>> + T: HasHrTimer<T>,
>> + T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
>> + Pin<Box<T, A>>: for<'a> RawHrTimerCallback<CallbackTarget<'a> = Pin<&'a T>>,
>
> I don't think this is necessary.
Should I remove it? I feel like it communicates intent.
>
>> + A: crate::alloc::Allocator,
>> +{
>> + type TimerHandle = BoxHrTimerHandle<T, A>;
>> +
>> + fn start(self, expires: Ktime) -> Self::TimerHandle {
>> + // SAFETY:
>> + // - We will not move out of this box during timer callback (we pass an
>> + // immutable reference to the callback).
>> + // - `Box::into_raw` is guaranteed to return a valid pointer.
>> + let inner =
>> + unsafe { NonNull::new_unchecked(Box::into_raw(Pin::into_inner_unchecked(self))) };
>> +
>> + // SAFETY:
>> + // - We keep `self` alive by wrapping it in a handle below.
>> + // - Since we generate the pointer passed to `start` from a valid
>> + // reference, it is a valid pointer.
>> + unsafe { T::start(inner.as_ptr(), expires) };
>> +
>> + BoxHrTimerHandle {
>> + inner,
>> + _p: core::marker::PhantomData,
>> + }
>> + }
>> +}
>> +
>> +impl<T, A> RawHrTimerCallback for Pin<Box<T, A>>
>> +where
>> + T: 'static,
>> + T: HasHrTimer<T>,
>> + T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
>> + A: crate::alloc::Allocator,
>> +{
>> + type CallbackTarget<'a> = Pin<&'a T>;
>
> Why isn't this `Pin<&'a mut T>`?
I don't think it matters much? There can be no other mutable references
while the callback is running, so why not a shared ref?
>
>> +
>> + unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
>> + // `HrTimer` is `repr(C)`
>> + let timer_ptr = ptr.cast::<super::HrTimer<T>>();
>> +
>> + // SAFETY: By C API contract `ptr` is the pointer we passed when
>> + // queuing the timer, so it is a `HrTimer<T>` embedded in a `T`.
>> + let data_ptr = unsafe { T::timer_container_of(timer_ptr) };
>> +
>> + // SAFETY: We called `Box::into_raw` when we queued the timer.
>> + let tbox = ManuallyDrop::new(Box::into_pin(unsafe { Box::<T, A>::from_raw(data_ptr) }));
>
> Since you turn this into a reference below and never run the drop, why
> not turn the pointer directly into a reference?
You mean replace with `unsafe {&*data_ptr};`? I guess that could work,
but it hinges on `Box` being transparent which is more subtle than going
through the API.
Best regards,
Andreas Hindborg
next prev parent reply other threads:[~2025-03-07 14:02 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-07 10:11 [PATCH v10 00/13] hrtimer Rust API Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 01/13] rust: hrtimer: introduce hrtimer support Andreas Hindborg
2025-03-07 12:43 ` Benno Lossin
2025-03-07 13:10 ` Andreas Hindborg
2025-03-07 13:46 ` Benno Lossin
2025-03-07 14:17 ` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 02/13] rust: sync: add `Arc::as_ptr` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 03/13] rust: hrtimer: implement `HrTimerPointer` for `Arc` Andreas Hindborg
2025-03-07 13:03 ` Benno Lossin
2025-03-07 13:27 ` Andreas Hindborg
2025-03-07 13:36 ` Benno Lossin
2025-03-07 14:16 ` Andreas Hindborg
2025-03-07 14:24 ` Benno Lossin
2025-03-07 10:11 ` [PATCH v10 04/13] rust: hrtimer: allow timer restart from timer handler Andreas Hindborg
2025-03-07 13:03 ` Benno Lossin
2025-03-07 10:11 ` [PATCH v10 05/13] rust: hrtimer: add `UnsafeHrTimerPointer` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 06/13] rust: hrtimer: add `hrtimer::ScopedHrTimerPointer` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 07/13] rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&T>` Andreas Hindborg
2025-03-07 13:12 ` Benno Lossin
2025-03-07 13:37 ` Andreas Hindborg
2025-03-07 13:51 ` Benno Lossin
2025-03-07 14:21 ` Andreas Hindborg
2025-03-07 14:25 ` Benno Lossin
2025-03-07 10:11 ` [PATCH v10 08/13] rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&mut T>` Andreas Hindborg
2025-03-07 13:15 ` Benno Lossin
2025-03-07 13:41 ` Andreas Hindborg
2025-03-07 13:49 ` Benno Lossin
2025-03-07 14:20 ` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 09/13] rust: alloc: add `Box::into_pin` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 10/13] rust: hrtimer: implement `HrTimerPointer` for `Pin<Box<T>>` Andreas Hindborg
2025-03-07 13:21 ` Benno Lossin
2025-03-07 14:01 ` Andreas Hindborg [this message]
2025-03-07 14:29 ` Benno Lossin
2025-03-07 15:33 ` Andreas Hindborg
2025-03-07 10:11 ` [PATCH v10 11/13] rust: hrtimer: add `HrTimerMode` Andreas Hindborg
2025-03-07 13:22 ` Benno Lossin
2025-03-07 10:11 ` [PATCH v10 12/13] rust: hrtimer: add clocksource selection through `ClockId` Andreas Hindborg
2025-03-07 13:23 ` Benno Lossin
2025-03-07 10:11 ` [PATCH v10 13/13] rust: hrtimer: add maintainer entry Andreas Hindborg
2025-03-07 13:28 ` Benno Lossin
2025-03-07 14:10 ` Andreas Hindborg
2025-03-07 14:14 ` Benno Lossin
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=87bjud3po0.fsf@kernel.org \
--to=a.hindborg@kernel.org \
--cc=2407018371@qq.com \
--cc=Markus.Elfring@web.de \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=anna-maria@linutronix.de \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dirk.behme@gmail.com \
--cc=frederic@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@gmail.com \
--cc=tglx@linutronix.de \
--cc=tmgross@umich.edu \
/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.