keos_project4/sync/
condition_variable.rs

1//! # Condition Variable.
2//!
3//! A **Condition Variable** allows a thread to efficiently block until a
4//! certain condition is met, without consuming CPU cycles. It is always used
5//! in conjunction with a [`Mutex`] that guards access to shared data. It is
6//! generally used when a thread needs to *wait for a specific state*
7//! in shared data, and another thread will *notify* it when that state changes.
8//!
9//! Condition variables enable complex synchronization patterns such as thread
10//! coordination, resource availability signaling, or implementing blocking
11//! queues.
12//!
13//! ## `ConditionVariable` in KeOS
14//! Condition variable must work with the shared [`Mutex`]. To enforce this,
15//! KeOS's [`ConditionVariable`] api takes either [`Mutex`] or [`MutexGuard`] as
16//! an argument. This enforces that the apis are called with a mutex, but does
17//! not fully ensure that the mutex is the associated one.
18//!
19//! The [`ConditionVariable::wait_while`] method automatically checks the
20//! predicate, blocks the current thread if the condition is true, and re-checks
21//! it upon wakeup. The method takes care of locking, checking the condition,
22//! blocking, and waking up:
23//!
24//! ```rust
25//! let guard = condvar.wait_while(&mutex, |state| state.is_empty());
26//! ```
27//!
28//! There are two signaling methods that takes the [`MutexGuard`]:
29//! - [`ConditionVariable::signal`] wakes **one** waiting thread and
30//! - [`ConditionVariable::broadcast`] wakes **all** waiting threads.
31//!
32//! ## Implementation Requirements
33//! You need to implement the followings:
34//! - [`ConditionVariable::wait_while`]
35//! - [`ConditionVariable::signal`]
36//! - [`ConditionVariable::broadcast`]
37//!
38//! After implement the functionalities, move on to the next [`section`].
39//!
40//! [`Mutex`]: crate::sync::Mutex
41//! [`section`]: crate::sync::semaphore
42
43use super::mutex::{Mutex, MutexGuard};
44use alloc::collections::vec_deque::VecDeque;
45use keos::{sync::SpinLock, thread::ParkHandle};
46
47/// A Condition Variable
48///
49/// Condition variables represent the ability to block a thread such that it
50/// consumes no CPU time while waiting for an event to occur. Condition
51/// variables are typically associated with a boolean predicate (a condition)
52/// and a mutex. The predicate is always verified inside of the mutex before
53/// determining that a thread must block.
54///
55/// Functions in this module will block the current **thread** of execution.
56/// Note that any attempt to use multiple mutexes on the same condition
57/// variable may result in a runtime panic.
58#[derive(Default)]
59pub struct ConditionVariable {
60    waiters: SpinLock<VecDeque<ParkHandle>>,
61}
62
63impl ConditionVariable {
64    /// Creates a new condition variable which is ready to be waited on and
65    /// signaled.
66    pub fn new() -> Self {
67        Self {
68            waiters: SpinLock::new(VecDeque::new()),
69        }
70    }
71
72    /// Blocks the current thread while `predicate` returns `true`.
73    ///
74    /// This function takes reference of a [`Mutex`] and checks the
75    /// predicate. If it returns `true`, the thread is blocked and the mutex is
76    /// temporarily released. When the thread is signaled and wakes up, it
77    /// reacquires the mutex and re-evaluates the predicate. This loop continues
78    /// until the predicate returns `false`.
79    ///
80    /// # Example
81    /// ```rust
82    /// let guard = condvar.wait_while(&mutex, |state| state.count == 0);
83    /// ```
84    ///
85    /// There is **no need to check the predicate before calling** `wait_while`.
86    /// It performs the entire check-and-sleep logic internally.
87    pub fn wait_while<'a, T>(
88        &self,
89        mutex: &'a Mutex<T>,
90        predicate: impl Fn(&mut T) -> bool,
91    ) -> MutexGuard<'a, T> {
92        todo!()
93    }
94
95    /// Wakes up one blocked thread on this condvar.
96    ///
97    /// If there is a blocked thread on this condition variable, then it will
98    /// be woken up from its call to [`wait_while`]. Calls to `signal` are not
99    /// buffered in any way.
100    ///
101    /// To wake up all threads, see [`broadcast`].
102    ///
103    /// [`broadcast`]: ConditionVariable::broadcast
104    /// [`wait_while`]: ConditionVariable::wait_while
105    pub fn signal<'a, T>(&self, guard: MutexGuard<'a, T>) {
106        todo!()
107    }
108
109    /// Wakes up all blocked threads on this condvar.
110    ///
111    /// This method will ensure that any current waiters on the condition
112    /// variable are awoken. Calls to `broadcast()` are not buffered in any
113    /// way.
114    ///
115    /// To wake up only one thread, see [`signal`].
116    ///
117    /// [`signal`]: ConditionVariable::signal
118    pub fn broadcast<'a, T>(&self, guard: MutexGuard<'a, T>) {
119        todo!()
120    }
121}