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}