[PATCH 01/17] rust: sync: completion: add wait_for_completion_timeout()

John Hubbard <[email protected]>
Newsgroups dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Joel Fernandes <[email protected]>

A driver that runs an interrupt self-test during probe waits for the
handler to fire. wait_for_completion() has no timeout, so a broken
interrupt path stalls probe indefinitely. Add a timeout variant of
wait_for_completion().

Document the type invariant that Completion always holds an initialized
struct completion, and cite it in the SAFETY comments.

Signed-off-by: Joel Fernandes <[email protected]>
[jhubbard: return the remaining jiffies, document the type invariant,
 cite it in the SAFETY comments]
Signed-off-by: John Hubbard <[email protected]>
---
 rust/kernel/sync/completion.rs | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs
index 35ff049ff078..b443c4999493 100644
--- a/rust/kernel/sync/completion.rs
+++ b/rust/kernel/sync/completion.rs
@@ -6,13 +6,22 @@
 //!
 //! C header: [`include/linux/completion.h`](srctree/include/linux/completion.h)
 
-use crate::{bindings, prelude::*, types::Opaque};
+use crate::{
+    bindings,
+    prelude::*,
+    time::Jiffies,
+    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.
 ///
+/// # Invariants
+///
+/// `inner` always holds an initialized `struct completion`.
+///
 /// # Examples
 ///
 /// ```
@@ -96,7 +105,8 @@ fn as_raw(&self) -> *mut bindings::completion {
     /// 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`.
+        // SAFETY: By the type invariant, `self.as_raw()` is a pointer to an initialized
+        // `struct completion`.
         unsafe { bindings::complete_all(self.as_raw()) };
     }
 
@@ -108,7 +118,25 @@ pub fn complete_all(&self) {
     /// See also [`Completion::complete_all`].
     #[inline]
     pub fn wait_for_completion(&self) {
-        // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`.
+        // SAFETY: By the type invariant, `self.as_raw()` is a pointer to an initialized
+        // `struct completion`.
         unsafe { bindings::wait_for_completion(self.as_raw()) };
     }
+
+    /// Wait for completion of a task, with a timeout.
+    ///
+    /// This method waits for the completion of a task, or until `timeout` elapses. It is not
+    /// interruptible. Returns the number of jiffies left when the task completed, or [`None`] if
+    /// `timeout` elapsed first.
+    ///
+    /// See also [`Completion::complete_all`].
+    #[inline]
+    pub fn wait_for_completion_timeout(&self, timeout: Jiffies) -> Option<Jiffies> {
+        // SAFETY: By the type invariant, `self.as_raw()` is a pointer to an initialized
+        // `struct completion`.
+        match unsafe { bindings::wait_for_completion_timeout(self.as_raw(), timeout) } {
+            0 => None,
+            remaining => Some(remaining),
+        }
+    }
 }
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.