114 lines · 3.3 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 //! Completion support.//!//! Reference: <https://docs.kernel.org/scheduler/completion.html>//!//! C header: [`include/linux/completion.h`](srctree/include/linux/completion.h) use crate::{bindings, prelude::*, types::Opaque}; /// Synchronization primitive to signal when a certain task has been completed.////// The [`Completion`] synchronization primitive signals when a certain task has been completed by/// waking up other tasks that have been queued up to wait for the [`Completion`] to be completed.////// # Examples////// ```/// use kernel::sync::{Arc, Completion};/// use kernel::workqueue::{self, impl_has_work, new_work, Work, WorkItem};////// #[pin_data]/// struct MyTask {///     #[pin]///     work: Work<MyTask>,///     #[pin]///     done: Completion,/// }////// impl_has_work! {///     impl HasWork<Self> for MyTask { self.work }/// }////// impl MyTask {///     fn new() -> Result<Arc<Self>> {///         let this = Arc::pin_init(pin_init!(MyTask {///             work <- new_work!("MyTask::work"),///             done <- Completion::new(),///         }), GFP_KERNEL)?;//////         let _ = workqueue::system().enqueue(this.clone());//////         Ok(this)///     }//////     fn wait_for_completion(&self) {///         self.done.wait_for_completion();//////         pr_info!("Completion: task complete\n");///     }/// }////// impl WorkItem for MyTask {///     type Pointer = Arc<MyTask>;//////     fn run(this: Arc<MyTask>) {///         // process this task///         this.done.complete_all();///     }/// }////// let task = MyTask::new()?;/// task.wait_for_completion();/// # Ok::<(), Error>(())/// ```#[pin_data]pub struct Completion {    #[pin]    inner: Opaque<bindings::completion>,} // SAFETY: `Completion` is safe to be send to any task.unsafe impl Send for Completion {} // SAFETY: `Completion` is safe to be accessed concurrently.unsafe impl Sync for Completion {} impl Completion {    /// Create an initializer for a new [`Completion`].    pub fn new() -> impl PinInit<Self> {        pin_init!(Self {            inner <- Opaque::ffi_init(|slot: *mut bindings::completion| {                // SAFETY: `slot` is a valid pointer to an uninitialized `struct completion`.                unsafe { bindings::init_completion(slot) };            }),        })    }     fn as_raw(&self) -> *mut bindings::completion {        self.inner.get()    }     /// Signal all tasks waiting on this completion.    ///    /// This method wakes up all tasks waiting on this completion; after this operation the    /// completion is permanently done, i.e. signals all current and future waiters.    #[inline]    pub fn complete_all(&self) {        // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.        unsafe { bindings::complete_all(self.as_raw()) };    }     /// Wait for completion of a task.    ///    /// This method waits for the completion of a task; it is not interruptible and there is no    /// timeout.    ///    /// See also [`Completion::complete_all`].    #[inline]    pub fn wait_for_completion(&self) {        // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.        unsafe { bindings::wait_for_completion(self.as_raw()) };    }}