Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 3525914

Browse files
DarksonnTreehugger Robot
authored and
Treehugger Robot
committed
UPSTREAM: 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 <[email protected]> Signed-off-by: Gary Guo <[email protected]> Signed-off-by: Alice Ryhl <[email protected]> Reviewed-by: Martin Rodriguez Reboredo <[email protected]> Reviewed-by: "Andreas Hindborg (Samsung)" <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Reviewed-by: Boqun Feng <[email protected]> Signed-off-by: Tejun Heo <[email protected]> [ Upstream commit 115c95e ] Change-Id: I9f7206d123636c420222085a3f16a2d688b97443 Signed-off-by: Alice Ryhl <[email protected]>
1 parent 7b431db commit 3525914

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

rust/kernel/workqueue.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
//! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
3030
3131
use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
32+
use alloc::alloc::AllocError;
3233
use alloc::boxed::Box;
3334
use core::marker::PhantomData;
3435
use core::pin::Pin;
@@ -96,6 +97,44 @@ impl Queue {
9697
})
9798
}
9899
}
100+
101+
/// Tries to spawn the given function or closure as a work item.
102+
///
103+
/// This method can fail because it allocates memory to store the work item.
104+
pub fn try_spawn<T: 'static + Send + FnOnce()>(&self, func: T) -> Result<(), AllocError> {
105+
let init = pin_init!(ClosureWork {
106+
work <- new_work!("Queue::try_spawn"),
107+
func: Some(func),
108+
});
109+
110+
self.enqueue(Box::pin_init(init).map_err(|_| AllocError)?);
111+
Ok(())
112+
}
113+
}
114+
115+
/// A helper type used in `try_spawn`.
116+
#[pin_data]
117+
struct ClosureWork<T> {
118+
#[pin]
119+
work: Work<ClosureWork<T>>,
120+
func: Option<T>,
121+
}
122+
123+
impl<T> ClosureWork<T> {
124+
fn project(self: Pin<&mut Self>) -> &mut Option<T> {
125+
// SAFETY: The `func` field is not structurally pinned.
126+
unsafe { &mut self.get_unchecked_mut().func }
127+
}
128+
}
129+
130+
impl<T: FnOnce()> WorkItem for ClosureWork<T> {
131+
type Pointer = Pin<Box<Self>>;
132+
133+
fn run(mut this: Pin<Box<Self>>) {
134+
if let Some(func) = this.as_mut().project().take() {
135+
(func)()
136+
}
137+
}
99138
}
100139

101140
/// A raw work item.
@@ -365,6 +404,10 @@ macro_rules! impl_has_work {
365404
)*};
366405
}
367406

407+
impl_has_work! {
408+
impl<T> HasWork<Self> for ClosureWork<T> { self.work }
409+
}
410+
368411
unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T>
369412
where
370413
T: WorkItem<ID, Pointer = Self>,

0 commit comments

Comments
 (0)