kernel/sync/completion.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Completion support.
4//!
5//! Reference: <https://docs.kernel.org/scheduler/completion.html>
6//!
7//! C header: [`include/linux/completion.h`](srctree/include/linux/completion.h)
8
9use crate::{bindings, prelude::*, types::Opaque};
10
11/// Synchronization primitive to signal when a certain task has been completed.
12///
13/// The [`Completion`] synchronization primitive signals when a certain task has been completed by
14/// waking up other tasks that have been queued up to wait for the [`Completion`] to be completed.
15///
16/// # Examples
17///
18/// ```
19/// use kernel::sync::{Arc, Completion};
20/// use kernel::workqueue::{self, impl_has_work, new_work, Work, WorkItem};
21///
22/// #[pin_data]
23/// struct MyTask {
24/// #[pin]
25/// work: Work<MyTask>,
26/// #[pin]
27/// done: Completion,
28/// }
29///
30/// impl_has_work! {
31/// impl HasWork<Self> for MyTask { self.work }
32/// }
33///
34/// impl MyTask {
35/// fn new() -> Result<Arc<Self>> {
36/// let this = Arc::pin_init(pin_init!(MyTask {
37/// work <- new_work!("MyTask::work"),
38/// done <- Completion::new(),
39/// }), GFP_KERNEL)?;
40///
41/// let _ = workqueue::system().enqueue(this.clone());
42///
43/// Ok(this)
44/// }
45///
46/// fn wait_for_completion(&self) {
47/// self.done.wait_for_completion();
48///
49/// pr_info!("Completion: task complete\n");
50/// }
51/// }
52///
53/// impl WorkItem for MyTask {
54/// type Pointer = Arc<MyTask>;
55///
56/// fn run(this: Arc<MyTask>) {
57/// // process this task
58/// this.done.complete_all();
59/// }
60/// }
61///
62/// let task = MyTask::new()?;
63/// task.wait_for_completion();
64/// # Ok::<(), Error>(())
65/// ```
66#[pin_data]
67pub struct Completion {
68 #[pin]
69 inner: Opaque<bindings::completion>,
70}
71
72// SAFETY: `Completion` is safe to be send to any task.
73unsafe impl Send for Completion {}
74
75// SAFETY: `Completion` is safe to be accessed concurrently.
76unsafe impl Sync for Completion {}
77
78impl Completion {
79 /// Create an initializer for a new [`Completion`].
80 pub fn new() -> impl PinInit<Self> {
81 pin_init!(Self {
82 inner <- Opaque::ffi_init(|slot: *mut bindings::completion| {
83 // SAFETY: `slot` is a valid pointer to an uninitialized `struct completion`.
84 unsafe { bindings::init_completion(slot) };
85 }),
86 })
87 }
88
89 fn as_raw(&self) -> *mut bindings::completion {
90 self.inner.get()
91 }
92
93 /// Signal all tasks waiting on this completion.
94 ///
95 /// This method wakes up all tasks waiting on this completion; after this operation the
96 /// completion is permanently done, i.e. signals all current and future waiters.
97 pub fn complete_all(&self) {
98 // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.
99 unsafe { bindings::complete_all(self.as_raw()) };
100 }
101
102 /// Wait for completion of a task.
103 ///
104 /// This method waits for the completion of a task; it is not interruptible and there is no
105 /// timeout.
106 ///
107 /// See also [`Completion::complete_all`].
108 pub fn wait_for_completion(&self) {
109 // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.
110 unsafe { bindings::wait_for_completion(self.as_raw()) };
111 }
112}