Skip to content

Commit

Permalink
rust: workqueue: add try_spawn helper method
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Darksonn authored and intel-lab-lkp committed May 17, 2023
1 parent e519eb0 commit c7bcf1f
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions rust/kernel/workqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit c7bcf1f

Please sign in to comment.