/rust/registry/src/index.crates.io-1949cf8c6b5b557f/mea-0.6.0/src/condvar/mod.rs
Line | Count | Source |
1 | | // Copyright 2024 tison <wander4096@gmail.com> |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | //! A condition variable that allows tasks to wait for a notification. |
16 | | //! |
17 | | //! # Examples |
18 | | //! |
19 | | //! ``` |
20 | | //! # #[tokio::main] |
21 | | //! # async fn main() { |
22 | | //! use std::sync::Arc; |
23 | | //! |
24 | | //! use mea::condvar::Condvar; |
25 | | //! use mea::mutex::Mutex; |
26 | | //! |
27 | | //! let pair = Arc::new((Mutex::new(false), Condvar::new())); |
28 | | //! let pair_clone = pair.clone(); |
29 | | //! |
30 | | //! // Inside our lock, spawn a new thread, and then wait for it to start. |
31 | | //! tokio::spawn(async move { |
32 | | //! let (lock, cvar) = &*pair_clone; |
33 | | //! let mut started = lock.lock().await; |
34 | | //! *started = true; |
35 | | //! // We notify the condvar that the value has changed. |
36 | | //! cvar.notify_one(); |
37 | | //! }); |
38 | | //! |
39 | | //! // Wait for the thread to start up. |
40 | | //! let (lock, cvar) = &*pair; |
41 | | //! let mut started = lock.lock().await; |
42 | | //! while !*started { |
43 | | //! started = cvar.wait(started).await; |
44 | | //! } |
45 | | //! # } |
46 | | //! ``` |
47 | | |
48 | | use std::fmt; |
49 | | use std::task::Waker; |
50 | | |
51 | | use crate::internal; |
52 | | use crate::mutex; |
53 | | use crate::mutex::MutexGuard; |
54 | | use crate::mutex::OwnedMutexGuard; |
55 | | |
56 | | #[cfg(test)] |
57 | | mod tests; |
58 | | |
59 | | /// A condition variable that allows tasks to wait for a notification. |
60 | | /// |
61 | | /// See the [module level documentation](self) for more. |
62 | | pub struct Condvar { |
63 | | s: internal::Semaphore, |
64 | | } |
65 | | |
66 | | impl fmt::Debug for Condvar { |
67 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
68 | 0 | f.debug_struct("Condvar").finish_non_exhaustive() |
69 | 0 | } |
70 | | } |
71 | | |
72 | | impl Default for Condvar { |
73 | 0 | fn default() -> Self { |
74 | 0 | Self::new() |
75 | 0 | } |
76 | | } |
77 | | |
78 | | impl Condvar { |
79 | | /// Creates a new condition variable |
80 | | /// |
81 | | /// # Examples |
82 | | /// |
83 | | /// ``` |
84 | | /// use mea::condvar::Condvar; |
85 | | /// |
86 | | /// let cvar = Condvar::new(); |
87 | | /// ``` |
88 | 0 | pub const fn new() -> Condvar { |
89 | 0 | Condvar { |
90 | 0 | s: internal::Semaphore::new(0), |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | | /// Wakes up one blocked task on this condvar. |
95 | 0 | pub fn notify_one(&self) { |
96 | 0 | self.s.release(1); |
97 | 0 | } |
98 | | |
99 | | /// Wakes up all blocked tasks on this condvar. |
100 | 0 | pub fn notify_all(&self) { |
101 | 0 | self.s.notify_all(); |
102 | 0 | } |
103 | | |
104 | | /// Yields the current task until this condition variable receives a notification. |
105 | | /// |
106 | | /// Unlike the std equivalent, this does not check that a single mutex is used at runtime. |
107 | | /// However, as a best practice avoid using with multiple mutexes. |
108 | 0 | pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { |
109 | 0 | let mutex = mutex::guard_lock(&guard); |
110 | | |
111 | | // register waiter while holding lock |
112 | 0 | let mut acquire = self.s.poll_acquire(1); |
113 | 0 | let _ = acquire.poll_once(Waker::noop()); |
114 | 0 | drop(guard); |
115 | | |
116 | | // await for notification, and then reacquire the lock |
117 | 0 | acquire.await; |
118 | 0 | mutex.lock().await |
119 | 0 | } |
120 | | |
121 | | /// Yields the current task until this condition variable receives a notification. |
122 | | /// |
123 | | /// Unlike the std equivalent, this does not check that a single mutex is used at runtime. |
124 | | /// However, as a best practice avoid using with multiple mutexes. |
125 | 0 | pub async fn wait_owned<T>(&self, guard: OwnedMutexGuard<T>) -> OwnedMutexGuard<T> { |
126 | 0 | let mutex = mutex::owned_guard_lock(&guard); |
127 | | |
128 | | // register waiter while holding lock |
129 | 0 | let mut acquire = self.s.poll_acquire(1); |
130 | 0 | let _ = acquire.poll_once(Waker::noop()); |
131 | 0 | drop(guard); |
132 | | |
133 | | // await for notification, and then reacquire the lock |
134 | 0 | acquire.await; |
135 | 0 | mutex.lock_owned().await |
136 | 0 | } |
137 | | |
138 | | /// Yields the current task until this condition variable receives a notification and the |
139 | | /// provided condition becomes false. Spurious wake-ups are ignored and this function will only |
140 | | /// return once the condition has been met. |
141 | | /// |
142 | | /// ``` |
143 | | /// # #[tokio::main] |
144 | | /// # async fn main() { |
145 | | /// use std::sync::Arc; |
146 | | /// |
147 | | /// use mea::condvar::Condvar; |
148 | | /// use mea::mutex::Mutex; |
149 | | /// |
150 | | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); |
151 | | /// let pair_clone = pair.clone(); |
152 | | /// |
153 | | /// tokio::spawn(async move { |
154 | | /// let (lock, cvar) = &*pair_clone; |
155 | | /// let mut started = lock.lock().await; |
156 | | /// *started = true; |
157 | | /// // We notify the condvar that the value has changed. |
158 | | /// cvar.notify_one(); |
159 | | /// }); |
160 | | /// |
161 | | /// // Wait for the thread to start up. |
162 | | /// let (lock, cvar) = &*pair; |
163 | | /// // As long as the value inside the `Mutex<bool>` is `false`, we wait. |
164 | | /// let guard = cvar |
165 | | /// .wait_while(lock.lock().await, |started| !*started) |
166 | | /// .await; |
167 | | /// assert!(*guard); |
168 | | /// # } |
169 | | /// ``` |
170 | 0 | pub async fn wait_while<'a, T, F>( |
171 | 0 | &self, |
172 | 0 | mut guard: MutexGuard<'a, T>, |
173 | 0 | mut condition: F, |
174 | 0 | ) -> MutexGuard<'a, T> |
175 | 0 | where |
176 | 0 | F: FnMut(&mut T) -> bool, |
177 | 0 | { |
178 | 0 | while condition(&mut *guard) { |
179 | 0 | guard = self.wait(guard).await; |
180 | | } |
181 | 0 | guard |
182 | 0 | } |
183 | | |
184 | | /// Yields the current task until this condition variable receives a notification and the |
185 | | /// provided condition becomes false. Spurious wake-ups are ignored and this function will only |
186 | | /// return once the condition has been met. |
187 | | /// |
188 | | /// ``` |
189 | | /// # #[tokio::main] |
190 | | /// # async fn main() { |
191 | | /// use std::sync::Arc; |
192 | | /// |
193 | | /// use mea::condvar::Condvar; |
194 | | /// use mea::mutex::Mutex; |
195 | | /// |
196 | | /// let pair = (Arc::new(Mutex::new(false)), Arc::new(Condvar::new())); |
197 | | /// let pair_clone = pair.clone(); |
198 | | /// |
199 | | /// tokio::spawn(async move { |
200 | | /// let (lock, cvar) = pair_clone; |
201 | | /// let mut started = lock.lock_owned().await; |
202 | | /// *started = true; |
203 | | /// // We notify the condvar that the value has changed. |
204 | | /// cvar.notify_one(); |
205 | | /// }); |
206 | | /// |
207 | | /// // Wait for the thread to start up. |
208 | | /// let (lock, cvar) = pair; |
209 | | /// // As long as the value inside the `Mutex<bool>` is `false`, we wait. |
210 | | /// let guard = cvar |
211 | | /// .wait_while_owned(lock.lock_owned().await, |started| !*started) |
212 | | /// .await; |
213 | | /// assert!(*guard); |
214 | | /// # } |
215 | | /// ``` |
216 | 0 | pub async fn wait_while_owned<T, F>( |
217 | 0 | &self, |
218 | 0 | mut guard: OwnedMutexGuard<T>, |
219 | 0 | mut condition: F, |
220 | 0 | ) -> OwnedMutexGuard<T> |
221 | 0 | where |
222 | 0 | F: FnMut(&mut T) -> bool, |
223 | 0 | { |
224 | 0 | while condition(&mut *guard) { |
225 | 0 | guard = self.wait_owned(guard).await; |
226 | | } |
227 | 0 | guard |
228 | 0 | } |
229 | | } |