Skip to content

Commit 8455599

Browse files
committed
zephyr: Add sync::Condvar
Add the high-level `sync::Condvar` to go along with `sync::Mutex` for thread synchronization. Signed-off-by: David Brown <[email protected]>
1 parent 34a0fab commit 8455599

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

zephyr/src/sync.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,74 @@ impl<T: ?Sized> Drop for MutexGuard<'_, T> {
145145
self.lock.inner.unlock().unwrap();
146146
}
147147
}
148+
149+
/// Inspired by
150+
/// [`std::sync::Condvar`](https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html),
151+
/// implemented directly using `z_condvar` in Zephyr.
152+
///
153+
/// Condition variables represent the ability to block a thread such that it consumes no CPU time
154+
/// while waiting for an even to occur. Condition variables are typically associated with a
155+
/// boolean predicate (a condition) and a mutex. The predicate is always verified inside of the
156+
/// mutex before determining that a thread must block.
157+
///
158+
/// Functions in this module will block the current **thread** of execution. Note that any attempt
159+
/// to use multiple mutexces on the same condition variable may result in a runtime panic.
160+
pub struct Condvar {
161+
inner: sys::Condvar,
162+
}
163+
164+
impl Condvar {
165+
/// Construct a new wrapped Condvar, using the given underlying `k_condvar`.
166+
///
167+
/// This is different from `std::sync::Condvar` in that in Zephyr, objects are frequently
168+
/// allocated statically, and the sys Condvar will be taken by this structure.
169+
pub const fn new_from(raw_condvar: sys::Condvar) -> Condvar {
170+
Condvar { inner: raw_condvar }
171+
}
172+
173+
/// Blocks the current thread until this conditional variable receives a notification.
174+
///
175+
/// This function will automatically unlock the mutex specified (represented by `guard`) and
176+
/// block the current thread. This means that any calls to `notify_one` or `notify_all` which
177+
/// happen logically after the mutex is unlocked are candidates to wake this thread up. When
178+
/// this function call returns, the lock specified will have been re-equired.
179+
///
180+
/// Note that this function is susceptable to spurious wakeups. Condition variables normally
181+
/// have a boolean predicate associated with them, and the predicate must always be checked
182+
/// each time this function returns to protect against spurious wakeups.
183+
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
184+
self.inner.wait(&guard.lock.inner);
185+
Ok(guard)
186+
}
187+
188+
// TODO: wait_while
189+
// TODO: wait_timeout_ms
190+
// TODO: wait_timeout
191+
// TODO: wait_timeout_while
192+
193+
/// Wakes up one blocked thread on this condvar.
194+
///
195+
/// If there is a blocked thread on this condition variable, then it will be woken up from its
196+
/// call to `wait` or `wait_timeout`. Calls to `notify_one` are not buffered in any way.
197+
///
198+
/// To wakeup all threads, see `notify_all`.
199+
pub fn notify_one(&self) {
200+
self.inner.notify_one();
201+
}
202+
203+
/// Wakes up all blocked threads on this condvar.
204+
///
205+
/// This methods will ensure that any current waiters on the condition variable are awoken.
206+
/// Calls to `notify_all()` are not buffered in any way.
207+
///
208+
/// To wake up only one thread, see `notify_one`.
209+
pub fn notify_all(&self) {
210+
self.inner.notify_all();
211+
}
212+
}
213+
214+
impl fmt::Debug for Condvar {
215+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216+
write!(f, "Condvar {:?}", self.inner)
217+
}
218+
}

0 commit comments

Comments
 (0)