Commit 1b56e765 authored by Danilo Krummrich's avatar Danilo Krummrich
Browse files

rust: completion: implement initial abstraction



Implement a minimal abstraction for the completion synchronization
primitive.

This initial abstraction only adds complete_all() and
wait_for_completion(), since that is what is required for the subsequent
Devres patch.

Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ben Segall <bsegall@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Valentin Schneider <vschneid@redhat.com>
Reviewed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Reviewed-by: default avatarBoqun Feng <boqun.feng@gmail.com>
Reviewed-by: default avatarBenno Lossin <lossin@kernel.org>
Acked-by: default avatarMiguel Ojeda <ojeda@kernel.org>
Link: https://lore.kernel.org/r/20250612121817.1621-2-dakr@kernel.org


Signed-off-by: default avatarDanilo Krummrich <dakr@kernel.org>
parent 19272b37
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <linux/blk_types.h>
#include <linux/blkdev.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/configfs.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
+8 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <linux/completion.h>

void rust_helper_init_completion(struct completion *x)
{
	init_completion(x);
}
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include "build_assert.c"
#include "build_bug.c"
#include "clk.c"
#include "completion.c"
#include "cpufreq.c"
#include "cpumask.c"
#include "cred.c"
+2 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
use pin_init;

mod arc;
pub mod completion;
mod condvar;
pub mod lock;
mod locked_by;
@@ -17,6 +18,7 @@
pub mod rcu;

pub use arc::{Arc, ArcBorrow, UniqueArc};
pub use completion::Completion;
pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
pub use lock::mutex::{new_mutex, Mutex, MutexGuard};
+112 −0
Original line number Diff line number Diff line
// 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.
    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`].
    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()) };
    }
}