Messages in this thread Patch in this message | | | Date | Wed, 17 May 2023 20:31:19 +0000 | Subject | [PATCH v1 7/7] rust: workqueue: add `try_spawn` helper method | From | Alice Ryhl <> |
| |
This adds a convenience method that lets you spawn a closure for execution on a workqueue. This will be the most convenient way to use workqueues, but it is fallible because it needs to allocate memory.
Signed-off-by: Alice Ryhl <aliceryhl@google.com> --- rust/kernel/workqueue.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 007005ddcaf0..303b72efd95f 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -57,6 +57,42 @@ impl Queue { }) } } + + /// Tries to spawn the given function or closure as a work item. + /// + /// This method can fail because it allocates memory to store the work item. + pub fn try_spawn<T: 'static + Send + Fn()>(&self, func: T) -> Result { + let init = pin_init!(ClosureWork { + work <- Work::new(), + func: Some(func), + }); + + self.enqueue(Box::pin_init(init)?); + Ok(()) + } +} + +/// A helper type used in `try_spawn`. +#[pin_data] +struct ClosureWork<T> { + #[pin] + work: Work<Pin<Box<ClosureWork<T>>>>, + func: Option<T>, +} + +impl<T> ClosureWork<T> { + fn project(self: Pin<&mut Self>) -> &mut Option<T> { + // SAFETY: The `func` field is not structurally pinned. + unsafe { &mut self.get_unchecked_mut().func } + } +} + +impl<T: FnOnce()> BoxWorkItem for ClosureWork<T> { + fn run(mut self: Pin<Box<Self>>) { + if let Some(func) = self.as_mut().project().take() { + (func)() + } + } } /// A work item. @@ -280,6 +316,10 @@ macro_rules! impl_has_work { )*}; } +impl_has_work! { + impl<T> HasWork<Pin<Box<Self>>> for ClosureWork<T> { self.work } +} + /// Declares that [`Arc<Self>`] should implement [`WorkItem`]. /// /// # Examples -- 2.40.1.606.ga4b1b128d6-goog
| |