From 115c95e9e14c482682080598907e6a18091fd0af Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 28 Aug 2023 10:48:06 +0000 Subject: rust: workqueue: add `try_spawn` helper method 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. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: "Andreas Hindborg (Samsung)" Reviewed-by: Benno Lossin Reviewed-by: Boqun Feng Signed-off-by: Tejun Heo --- rust/kernel/workqueue.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'rust') diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index c1334c48b96b..40ccc53f6e93 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -29,6 +29,7 @@ //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h) use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque}; +use alloc::alloc::AllocError; use alloc::boxed::Box; use core::marker::PhantomData; use core::pin::Pin; @@ -96,6 +97,44 @@ 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(&self, func: T) -> Result<(), AllocError> { + let init = pin_init!(ClosureWork { + work <- new_work!("Queue::try_spawn"), + func: Some(func), + }); + + self.enqueue(Box::pin_init(init).map_err(|_| AllocError)?); + Ok(()) + } +} + +/// A helper type used in `try_spawn`. +#[pin_data] +struct ClosureWork { + #[pin] + work: Work>, + func: Option, +} + +impl ClosureWork { + fn project(self: Pin<&mut Self>) -> &mut Option { + // SAFETY: The `func` field is not structurally pinned. + unsafe { &mut self.get_unchecked_mut().func } + } +} + +impl WorkItem for ClosureWork { + type Pointer = Pin>; + + fn run(mut this: Pin>) { + if let Some(func) = this.as_mut().project().take() { + (func)() + } + } } /// A raw work item. @@ -365,6 +404,10 @@ macro_rules! impl_has_work { )*}; } +impl_has_work! { + impl HasWork for ClosureWork { self.work } +} + unsafe impl WorkItemPointer for Arc where T: WorkItem, -- cgit