Skip to content

Commit 1b56e76

Browse files
author
Danilo Krummrich
committed
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 <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Juri Lelli <[email protected]> Cc: Vincent Guittot <[email protected]> Cc: Dietmar Eggemann <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Ben Segall <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Valentin Schneider <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Boqun Feng <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Acked-by: Miguel Ojeda <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 19272b3 commit 1b56e76

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <linux/blk_types.h>
4040
#include <linux/blkdev.h>
4141
#include <linux/clk.h>
42+
#include <linux/completion.h>
4243
#include <linux/configfs.h>
4344
#include <linux/cpu.h>
4445
#include <linux/cpufreq.h>

rust/helpers/completion.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/completion.h>
4+
5+
void rust_helper_init_completion(struct completion *x)
6+
{
7+
init_completion(x);
8+
}

rust/helpers/helpers.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "build_assert.c"
1414
#include "build_bug.c"
1515
#include "clk.c"
16+
#include "completion.c"
1617
#include "cpufreq.c"
1718
#include "cpumask.c"
1819
#include "cred.c"

rust/kernel/sync.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ use crate::types::Opaque;
1010
use pin_init;
1111

1212
mod arc;
13+
pub mod completion;
1314
mod condvar;
1415
pub mod lock;
1516
mod locked_by;
1617
pub mod poll;
1718
pub mod rcu;
1819

1920
pub use arc::{Arc, ArcBorrow, UniqueArc};
21+
pub use completion::Completion;
2022
pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
2123
pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
2224
pub use lock::mutex::{new_mutex, Mutex, MutexGuard};

rust/kernel/sync/completion.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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+
9+
use 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]
67+
pub struct Completion {
68+
#[pin]
69+
inner: Opaque<bindings::completion>,
70+
}
71+
72+
// SAFETY: `Completion` is safe to be send to any task.
73+
unsafe impl Send for Completion {}
74+
75+
// SAFETY: `Completion` is safe to be accessed concurrently.
76+
unsafe impl Sync for Completion {}
77+
78+
impl 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+
}

0 commit comments

Comments
 (0)