From 405f1702451b50b80129868d07b6acaa3161b3c0 Mon Sep 17 00:00:00 2001 From: James Munns Date: Sat, 6 Jul 2024 20:17:40 +0200 Subject: [PATCH 01/10] Add `wait_for` and `wait_for_value` to WaitCell and WaitQueue --- maitake-sync/src/wait_cell.rs | 40 +++++++++++++++++++++++++++ maitake-sync/src/wait_queue.rs | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index 45ef4d17..e6a82eb4 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -327,6 +327,46 @@ impl WaitCell { } } + /// Asynchronously poll the [`WaitCell`] until a condition occurs + /// + /// This can be used to implement a "wait loop", turning a "try" function + /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. + /// "recv" or "send"). + /// + /// Consider using [`Self::wait_for_value()`] if your function does return a value. + /// + /// * Returns `Ok(T)` if the closure returns `Some(T)`. + /// * Returns `Err(Closed)` if the [`WaitCell`] is closed. + pub async fn wait_for bool>(&self, mut f: F) -> Result<(), Closed> { + loop { + let wait = self.subscribe().await; + if f() { + return Ok(()); + } + wait.await?; + } + } + + /// Asynchronously poll the [`WaitCell`] until a condition occurs + /// + /// This can be used to implement a "wait loop", turning a "try" function + /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. + /// "recv" or "send"). + /// + /// Consider using [`Self::wait_for()`] if your function does not return a value. + /// + /// * Returns `Ok(T)` if the closure returns `Some(T)`. + /// * Returns `Err(Closed)` if the [`WaitCell`] is closed. + pub async fn wait_for_value Option>(&self, mut f: F) -> Result { + loop { + let wait = self.subscribe().await; + if let Some(t) = f() { + return Ok(t); + } + wait.await?; + } + } + // TODO(eliza): is this an API we want to have? /* /// Returns `true` if this `WaitCell` is [closed](Self::close). diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index 9ed5100e..cc4a3ded 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -684,6 +684,56 @@ impl WaitQueue { } } + /// Asynchronously poll the [`WaitQueue`] until a condition occurs + /// + /// This can be used to implement a "wait loop", turning a "try" function + /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. + /// "recv" or "send"). + /// + /// Consider using [`Self::wait_for_value()`] if your function does return a value. + /// + /// * Returns `Ok(T)` if the closure returns `Some(T)`. + /// * Returns `Err(Closed)` if the [`WaitQueue`] is closed. + pub async fn wait_for bool>(&self, mut f: F) -> WaitResult<()> { + loop { + let wait = self.wait(); + let mut pwait = core::pin::pin!(wait); + match pwait.as_mut().subscribe() { + Poll::Ready(wr) => wr?, + Poll::Pending => {} + } + if f() { + return Ok(()); + } + pwait.await?; + } + } + + /// Asynchronously poll the [`WaitQueue`] until a condition occurs + /// + /// This can be used to implement a "wait loop", turning a "try" function + /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. + /// "recv" or "send"). + /// + /// Consider using [`Self::wait_for()`] if your function does not return a value. + /// + /// * Returns `Ok(T)` if the closure returns `Some(T)`. + /// * Returns `Err(Closed)` if the [`WaitQueue`] is closed. + pub async fn wait_for_value Option>(&self, mut f: F) -> WaitResult { + loop { + let wait = self.wait(); + let mut pwait = core::pin::pin!(wait); + match pwait.as_mut().subscribe() { + Poll::Ready(wr) => wr?, + Poll::Pending => {} + } + if let Some(t) = f() { + return Ok(t); + } + pwait.await?; + } + } + /// Returns a [`Waiter`] entry in this queue. /// /// This is factored out into a separate function because it's used by both From 0c870e035d019e2cf398f5dff3a0eff8d48aac9d Mon Sep 17 00:00:00 2001 From: James Munns Date: Sat, 6 Jul 2024 20:32:32 +0200 Subject: [PATCH 02/10] Fix docs --- maitake-sync/src/wait_cell.rs | 2 +- maitake-sync/src/wait_queue.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index e6a82eb4..4ead9dc2 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -335,7 +335,7 @@ impl WaitCell { /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// - /// * Returns `Ok(T)` if the closure returns `Some(T)`. + /// * Returns `Ok(())` if the closure returns `true`. /// * Returns `Err(Closed)` if the [`WaitCell`] is closed. pub async fn wait_for bool>(&self, mut f: F) -> Result<(), Closed> { loop { diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index cc4a3ded..339ff9b7 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -692,7 +692,7 @@ impl WaitQueue { /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// - /// * Returns `Ok(T)` if the closure returns `Some(T)`. + /// * Returns `Ok(())` if the closure returns `true`. /// * Returns `Err(Closed)` if the [`WaitQueue`] is closed. pub async fn wait_for bool>(&self, mut f: F) -> WaitResult<()> { loop { From 91b0405d6e4a09a0e5359952893c5558c863d02c Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 7 Jul 2024 20:30:48 +0200 Subject: [PATCH 03/10] Apply suggestions from code review Co-authored-by: Eliza Weisman --- maitake-sync/src/wait_cell.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index 4ead9dc2..0f4253a9 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -335,8 +335,10 @@ impl WaitCell { /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// - /// * Returns `Ok(())` if the closure returns `true`. - /// * Returns `Err(Closed)` if the [`WaitCell`] is closed. + /// # Returns + /// + /// * [`Ok`]`(())` if the closure returns `true`. + /// * [`Err`]`(`[`Closed`]`)` if the [`WaitCell`] is closed. pub async fn wait_for bool>(&self, mut f: F) -> Result<(), Closed> { loop { let wait = self.subscribe().await; @@ -355,8 +357,10 @@ impl WaitCell { /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// - /// * Returns `Ok(T)` if the closure returns `Some(T)`. - /// * Returns `Err(Closed)` if the [`WaitCell`] is closed. + /// # Returns + /// + /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. + /// * [`Err`]`(`[`Closed`]`)` if the [`WaitCell`] is closed. pub async fn wait_for_value Option>(&self, mut f: F) -> Result { loop { let wait = self.subscribe().await; From 312b5e5d6401d9688cdc9609737b151f44d2a818 Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 7 Jul 2024 20:31:31 +0200 Subject: [PATCH 04/10] Apply suggestions from code review Co-authored-by: Eliza Weisman --- maitake-sync/src/wait_queue.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index 339ff9b7..f7f22896 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -692,8 +692,10 @@ impl WaitQueue { /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// - /// * Returns `Ok(())` if the closure returns `true`. - /// * Returns `Err(Closed)` if the [`WaitQueue`] is closed. + /// # Returns + /// + /// * [`Ok`]`(())` if the closure returns `true`. + /// * [`Err`]`(`[`Closed`]`)` if the [`WaitQueue`] is closed. pub async fn wait_for bool>(&self, mut f: F) -> WaitResult<()> { loop { let wait = self.wait(); From c714a5607a0696f25ff71804b63e25d2d0c8d8e6 Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 7 Jul 2024 20:32:05 +0200 Subject: [PATCH 05/10] Apply suggestions from code review Co-authored-by: Eliza Weisman --- maitake-sync/src/wait_queue.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index f7f22896..f2ab48b2 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -700,10 +700,7 @@ impl WaitQueue { loop { let wait = self.wait(); let mut pwait = core::pin::pin!(wait); - match pwait.as_mut().subscribe() { - Poll::Ready(wr) => wr?, - Poll::Pending => {} - } + let _ = pwait.as_mut().subscribe()?; if f() { return Ok(()); } @@ -719,8 +716,8 @@ impl WaitQueue { /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// - /// * Returns `Ok(T)` if the closure returns `Some(T)`. - /// * Returns `Err(Closed)` if the [`WaitQueue`] is closed. + /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. + /// * [`Err`]`(`[`Closed`]`)` if the [`WaitQueue`] is closed. pub async fn wait_for_value Option>(&self, mut f: F) -> WaitResult { loop { let wait = self.wait(); From e7f627d580cf4fb53428f136b5bf2b341acf7855 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Jul 2024 19:11:51 +0200 Subject: [PATCH 06/10] Address review comments --- maitake-sync/src/wait_cell.rs | 115 ++++++++++++++++++++++++- maitake-sync/src/wait_queue.rs | 150 +++++++++++++++++++++++++++++++-- 2 files changed, 257 insertions(+), 8 deletions(-) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index 0f4253a9..e9704996 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -327,18 +327,70 @@ impl WaitCell { } } - /// Asynchronously poll the [`WaitCell`] until a condition occurs + /// Asynchronously poll the given function `f` until a condition occurs, + /// using the [`WaitCell`] to only re-poll when notified. /// /// This can be used to implement a "wait loop", turning a "try" function /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. /// "recv" or "send"). /// + /// In particular, this function correctly *registers* interest in the [`WaitCell`] + /// prior to polling the function, ensuring that there is not a chance of a race + /// where the condition occurs AFTER checking but BEFORE registering interest + /// in the [`WaitCell`], which could lead to deadlock. + /// + /// This is intended to have similar behavior to `Condvar` in the standard library, + /// but asynchronous, and not requiring operating system intervention (or existence). + /// + /// In particular, this can be used in cases where interrupts or events are used + /// to signify readiness or completion of some task, such as the completion of a + /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt + /// can wake the queue, allowing the polling function to check status fields for + /// partial progress or completion. + /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// + /// Consider using [`WaitQueue::wait_for()`] if you need multiple waiters. + /// /// # Returns /// /// * [`Ok`]`(())` if the closure returns `true`. /// * [`Err`]`(`[`Closed`]`)` if the [`WaitCell`] is closed. + /// + /// # Examples + /// + /// ``` + /// # use tokio::task; + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn test() { + /// use std::sync::Arc; + /// use maitake_sync::WaitCell; + /// use std::sync::atomic::{AtomicU8, Ordering}; + /// + /// let queue = Arc::new(WaitCell::new()); + /// let num = Arc::new(AtomicU8::new(0)); + /// + /// let waiter = task::spawn({ + /// // clone items to move into the spawned task + /// let queue = queue.clone(); + /// let num = num.clone(); + /// async move { + /// queue.wait_for(|| num.load(Ordering::Relaxed) > 5).await; + /// println!("received wakeup!"); + /// } + /// }); + /// + /// println!("poking task..."); + /// + /// for i in 0..20 { + /// num.store(i, Ordering::Relaxed); + /// queue.wake(); + /// } + /// + /// waiter.await.unwrap(); + /// # } + /// # test(); + /// ``` pub async fn wait_for bool>(&self, mut f: F) -> Result<(), Closed> { loop { let wait = self.subscribe().await; @@ -349,18 +401,75 @@ impl WaitCell { } } - /// Asynchronously poll the [`WaitCell`] until a condition occurs + /// Asynchronously poll the given function `f` until a condition occurs, + /// using the [`WaitCell`] to only re-poll when notified. /// /// This can be used to implement a "wait loop", turning a "try" function /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. /// "recv" or "send"). /// + /// In particular, this function correctly *registers* interest in the [`WaitCell`] + /// prior to polling the function, ensuring that there is not a chance of a race + /// where the condition occurs AFTER checking but BEFORE registering interest + /// in the [`WaitCell`], which could lead to deadlock. + /// + /// This is intended to have similar behavior to `Condvar` in the standard library, + /// but asynchronous, and not requiring operating system intervention (or existence). + /// + /// In particular, this can be used in cases where interrupts or events are used + /// to signify readiness or completion of some task, such as the completion of a + /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt + /// can wake the queue, allowing the polling function to check status fields for + /// partial progress or completion, and also return the status flags at the same time. + /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// - /// # Returns + /// Consider using [`WaitCell::wait_for_value()`] if you do not need multiple waiters. /// /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. /// * [`Err`]`(`[`Closed`]`)` if the [`WaitCell`] is closed. + /// + /// # Examples + /// + /// ``` + /// # use tokio::task; + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn test() { + /// use std::sync::Arc; + /// use maitake_sync::WaitCell; + /// use std::sync::atomic::{AtomicU8, Ordering}; + /// + /// let queue = Arc::new(WaitCell::new()); + /// let num = Arc::new(AtomicU8::new(0)); + /// + /// let waiter = task::spawn({ + /// // clone items to move into the spawned task + /// let queue = queue.clone(); + /// let num = num.clone(); + /// async move { + /// let rxd = queue.wait_for_value(|| { + /// let val = num.load(Ordering::Relaxed); + /// if val > 5 { + /// return Some(val); + /// } + /// None + /// }).await.unwrap(); + /// assert!(rxd > 5); + /// println!("received wakeup with value: {rxd}"); + /// } + /// }); + /// + /// println!("poking task..."); + /// + /// for i in 0..20 { + /// num.store(i, Ordering::Relaxed); + /// queue.wake(); + /// } + /// + /// waiter.await.unwrap(); + /// # } + /// # test(); + /// ``` pub async fn wait_for_value Option>(&self, mut f: F) -> Result { loop { let wait = self.subscribe().await; diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index f2ab48b2..05e11b77 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -684,40 +684,180 @@ impl WaitQueue { } } - /// Asynchronously poll the [`WaitQueue`] until a condition occurs + /// Asynchronously poll the given function `f` until a condition occurs, + /// using the [`WaitQueue`] to only re-poll when notified. /// /// This can be used to implement a "wait loop", turning a "try" function /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. /// "recv" or "send"). /// + /// In particular, this function correctly *registers* interest in the [`WaitQueue`] + /// prior to polling the function, ensuring that there is not a chance of a race + /// where the condition occurs AFTER checking but BEFORE registering interest + /// in the [`WaitQueue`], which could lead to deadlock. + /// + /// This is intended to have similar behavior to `Condvar` in the standard library, + /// but asynchronous, and not requiring operating system intervention (or existence). + /// + /// In particular, this can be used in cases where interrupts or events are used + /// to signify readiness or completion of some task, such as the completion of a + /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt + /// can wake the queue, allowing the polling function to check status fields for + /// partial progress or completion. + /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// + /// Consider using [`WaitCell::wait_for()`] if you do not need multiple waiters. + /// /// # Returns /// /// * [`Ok`]`(())` if the closure returns `true`. /// * [`Err`]`(`[`Closed`]`)` if the [`WaitQueue`] is closed. + /// + /// # Examples + /// + /// ``` + /// # use tokio::task; + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn test() { + /// use std::sync::Arc; + /// use maitake_sync::WaitQueue; + /// use std::sync::atomic::{AtomicU8, Ordering}; + /// + /// let queue = Arc::new(WaitQueue::new()); + /// let num = Arc::new(AtomicU8::new(0)); + /// + /// let waiter1 = task::spawn({ + /// // clone items to move into the spawned task + /// let queue = queue.clone(); + /// let num = num.clone(); + /// async move { + /// queue.wait_for(|| num.load(Ordering::Relaxed) > 5).await; + /// println!("received wakeup!"); + /// } + /// }); + /// + /// let waiter2 = task::spawn({ + /// // clone items to move into the spawned task + /// let queue = queue.clone(); + /// let num = num.clone(); + /// async move { + /// queue.wait_for(|| num.load(Ordering::Relaxed) > 10).await; + /// println!("received wakeup!"); + /// } + /// }); + /// + /// println!("poking task..."); + /// + /// for i in 0..20 { + /// num.store(i, Ordering::Relaxed); + /// queue.wake(); + /// } + /// + /// waiter1.await.unwrap(); + /// waiter2.await.unwrap(); + /// # } + /// # test(); + /// ``` pub async fn wait_for bool>(&self, mut f: F) -> WaitResult<()> { loop { let wait = self.wait(); - let mut pwait = core::pin::pin!(wait); - let _ = pwait.as_mut().subscribe()?; + let mut wait = core::pin::pin!(wait); + let _ = wait.as_mut().subscribe()?; if f() { return Ok(()); } - pwait.await?; + wait.await?; } } - /// Asynchronously poll the [`WaitQueue`] until a condition occurs + /// Asynchronously poll the given function `f` until a condition occurs, + /// using the [`WaitQueue`] to only re-poll when notified. /// /// This can be used to implement a "wait loop", turning a "try" function /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g. /// "recv" or "send"). /// + /// In particular, this function correctly *registers* interest in the [`WaitQueue`] + /// prior to polling the function, ensuring that there is not a chance of a race + /// where the condition occurs AFTER checking but BEFORE registering interest + /// in the [`WaitQueue`], which could lead to deadlock. + /// + /// This is intended to have similar behavior to `Condvar` in the standard library, + /// but asynchronous, and not requiring operating system intervention (or existence). + /// + /// In particular, this can be used in cases where interrupts or events are used + /// to signify readiness or completion of some task, such as the completion of a + /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt + /// can wake the queue, allowing the polling function to check status fields for + /// partial progress or completion, and also return the status flags at the same time. + /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// + /// Consider using [`WaitCell::wait_for_value()`] if you do not need multiple waiters. + /// /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. /// * [`Err`]`(`[`Closed`]`)` if the [`WaitQueue`] is closed. + /// + /// # Examples + /// + /// ``` + /// # use tokio::task; + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn test() { + /// use std::sync::Arc; + /// use maitake_sync::WaitQueue; + /// use std::sync::atomic::{AtomicU8, Ordering}; + /// + /// let queue = Arc::new(WaitQueue::new()); + /// let num = Arc::new(AtomicU8::new(0)); + /// + /// let waiter1 = task::spawn({ + /// // clone items to move into the spawned task + /// let queue = queue.clone(); + /// let num = num.clone(); + /// async move { + /// let rxd = queue.wait_for_value(|| { + /// let val = num.load(Ordering::Relaxed); + /// if val > 5 { + /// return Some(val); + /// } + /// None + /// }).await.unwrap(); + /// assert!(rxd > 5); + /// println!("received wakeup with value: {rxd}"); + /// } + /// }); + /// + /// let waiter2 = task::spawn({ + /// // clone items to move into the spawned task + /// let queue = queue.clone(); + /// let num = num.clone(); + /// async move { + /// let rxd = queue.wait_for_value(|| { + /// let val = num.load(Ordering::Relaxed); + /// if val > 10 { + /// return Some(val); + /// } + /// None + /// }).await.unwrap(); + /// assert!(rxd > 10); + /// println!("received wakeup with value: {rxd}"); + /// } + /// }); + /// + /// println!("poking task..."); + /// + /// for i in 0..20 { + /// num.store(i, Ordering::Relaxed); + /// queue.wake(); + /// } + /// + /// waiter1.await.unwrap(); + /// waiter2.await.unwrap(); + /// # } + /// # test(); + /// ``` pub async fn wait_for_value Option>(&self, mut f: F) -> WaitResult { loop { let wait = self.wait(); From ae0536ff4e246299e10edb46a591e9428f66aa45 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Jul 2024 19:13:33 +0200 Subject: [PATCH 07/10] Fix copy/paste error --- maitake-sync/src/wait_cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index e9704996..a53531e2 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -424,7 +424,7 @@ impl WaitCell { /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// - /// Consider using [`WaitCell::wait_for_value()`] if you do not need multiple waiters. + /// Consider using [`WaitQueue::wait_for_value()`] if you need multiple waiters. /// /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. /// * [`Err`]`(`[`Closed`]`)` if the [`WaitCell`] is closed. From 11e1b71d7313490e9f9622e56b5c1a84cc1ead1b Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Jul 2024 19:14:46 +0200 Subject: [PATCH 08/10] More copy/paste errors --- maitake-sync/src/wait_cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index a53531e2..fe328f21 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -345,7 +345,7 @@ impl WaitCell { /// In particular, this can be used in cases where interrupts or events are used /// to signify readiness or completion of some task, such as the completion of a /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt - /// can wake the queue, allowing the polling function to check status fields for + /// can wake the cell, allowing the polling function to check status fields for /// partial progress or completion. /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. @@ -419,7 +419,7 @@ impl WaitCell { /// In particular, this can be used in cases where interrupts or events are used /// to signify readiness or completion of some task, such as the completion of a /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt - /// can wake the queue, allowing the polling function to check status fields for + /// can wake the cell, allowing the polling function to check status fields for /// partial progress or completion, and also return the status flags at the same time. /// /// Consider using [`Self::wait_for()`] if your function does not return a value. From 5b5877f9e968b640bfe60ff338242739dee58ea5 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Jul 2024 19:15:49 +0200 Subject: [PATCH 09/10] shadow the hedgehog --- maitake-sync/src/wait_queue.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index 05e11b77..be106cc2 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -861,15 +861,15 @@ impl WaitQueue { pub async fn wait_for_value Option>(&self, mut f: F) -> WaitResult { loop { let wait = self.wait(); - let mut pwait = core::pin::pin!(wait); - match pwait.as_mut().subscribe() { + let mut wait = core::pin::pin!(wait); + match wait.as_mut().subscribe() { Poll::Ready(wr) => wr?, Poll::Pending => {} } if let Some(t) = f() { return Ok(t); } - pwait.await?; + wait.await?; } } From 6d31edd6ccb0c5a4d0f2b9a9b95b266060d142fa Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Jul 2024 19:31:37 +0200 Subject: [PATCH 10/10] Fix some tests and docs --- maitake-sync/src/wait_cell.rs | 5 +++-- maitake-sync/src/wait_queue.rs | 10 ++++++---- maitake/src/time/timer/tests.rs | 3 +++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/maitake-sync/src/wait_cell.rs b/maitake-sync/src/wait_cell.rs index fe328f21..802867c8 100644 --- a/maitake-sync/src/wait_cell.rs +++ b/maitake-sync/src/wait_cell.rs @@ -350,7 +350,8 @@ impl WaitCell { /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// - /// Consider using [`WaitQueue::wait_for()`] if you need multiple waiters. + /// Consider using [`WaitQueue::wait_for()`](super::wait_queue::WaitQueue::wait_for) + /// if you need multiple waiters. /// /// # Returns /// @@ -424,7 +425,7 @@ impl WaitCell { /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// - /// Consider using [`WaitQueue::wait_for_value()`] if you need multiple waiters. + /// Consider using [`WaitQueue::wait_for_value()`](super::wait_queue::WaitQueue::wait_for_value) if you need multiple waiters. /// /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. /// * [`Err`]`(`[`Closed`]`)` if the [`WaitCell`] is closed. diff --git a/maitake-sync/src/wait_queue.rs b/maitake-sync/src/wait_queue.rs index be106cc2..04843476 100644 --- a/maitake-sync/src/wait_queue.rs +++ b/maitake-sync/src/wait_queue.rs @@ -707,12 +707,13 @@ impl WaitQueue { /// /// Consider using [`Self::wait_for_value()`] if your function does return a value. /// - /// Consider using [`WaitCell::wait_for()`] if you do not need multiple waiters. + /// Consider using [`WaitCell::wait_for()`](super::wait_cell::WaitCell::wait_for) + /// if you do not need multiple waiters. /// /// # Returns /// /// * [`Ok`]`(())` if the closure returns `true`. - /// * [`Err`]`(`[`Closed`]`)` if the [`WaitQueue`] is closed. + /// * [`Err`]`(`[`Closed`](crate::Closed)`)` if the [`WaitQueue`] is closed. /// /// # Examples /// @@ -794,10 +795,11 @@ impl WaitQueue { /// /// Consider using [`Self::wait_for()`] if your function does not return a value. /// - /// Consider using [`WaitCell::wait_for_value()`] if you do not need multiple waiters. + /// Consider using [`WaitCell::wait_for_value()`](super::wait_cell::WaitCell::wait_for_value) + /// if you do not need multiple waiters. /// /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`. - /// * [`Err`]`(`[`Closed`]`)` if the [`WaitQueue`] is closed. + /// * [`Err`]`(`[`Closed`](crate::Closed)`)` if the [`WaitQueue`] is closed. /// /// # Examples /// diff --git a/maitake/src/time/timer/tests.rs b/maitake/src/time/timer/tests.rs index c121161a..e7a2baa2 100644 --- a/maitake/src/time/timer/tests.rs +++ b/maitake/src/time/timer/tests.rs @@ -5,6 +5,9 @@ use core::cell::RefCell; use core::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; +use crate::time::{Clock, timer::Ticks}; +use std::time::Duration; + crate::loom::thread_local! { static CLOCK: RefCell>> = RefCell::new(None); }