at v6.19-rc2 112 lines 3.3 kB view raw
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}