1*19096bceSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 2*19096bceSWedson Almeida Filho 3*19096bceSWedson Almeida Filho //! A condition variable. 4*19096bceSWedson Almeida Filho //! 5*19096bceSWedson Almeida Filho //! This module allows Rust code to use the kernel's [`struct wait_queue_head`] as a condition 6*19096bceSWedson Almeida Filho //! variable. 7*19096bceSWedson Almeida Filho 8*19096bceSWedson Almeida Filho use super::{lock::Backend, lock::Guard, LockClassKey}; 9*19096bceSWedson Almeida Filho use crate::{bindings, init::PinInit, pin_init, str::CStr, types::Opaque}; 10*19096bceSWedson Almeida Filho use core::marker::PhantomPinned; 11*19096bceSWedson Almeida Filho use macros::pin_data; 12*19096bceSWedson Almeida Filho 13*19096bceSWedson Almeida Filho /// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class. 14*19096bceSWedson Almeida Filho #[macro_export] 15*19096bceSWedson Almeida Filho macro_rules! new_condvar { 16*19096bceSWedson Almeida Filho ($($name:literal)?) => { 17*19096bceSWedson Almeida Filho $crate::sync::CondVar::new($crate::optional_name!($($name)?), $crate::static_lock_class!()) 18*19096bceSWedson Almeida Filho }; 19*19096bceSWedson Almeida Filho } 20*19096bceSWedson Almeida Filho 21*19096bceSWedson Almeida Filho /// A conditional variable. 22*19096bceSWedson Almeida Filho /// 23*19096bceSWedson Almeida Filho /// Exposes the kernel's [`struct wait_queue_head`] as a condition variable. It allows the caller to 24*19096bceSWedson Almeida Filho /// atomically release the given lock and go to sleep. It reacquires the lock when it wakes up. And 25*19096bceSWedson Almeida Filho /// it wakes up when notified by another thread (via [`CondVar::notify_one`] or 26*19096bceSWedson Almeida Filho /// [`CondVar::notify_all`]) or because the thread received a signal. It may also wake up 27*19096bceSWedson Almeida Filho /// spuriously. 28*19096bceSWedson Almeida Filho /// 29*19096bceSWedson Almeida Filho /// Instances of [`CondVar`] need a lock class and to be pinned. The recommended way to create such 30*19096bceSWedson Almeida Filho /// instances is with the [`pin_init`](crate::pin_init) and [`new_condvar`] macros. 31*19096bceSWedson Almeida Filho /// 32*19096bceSWedson Almeida Filho /// # Examples 33*19096bceSWedson Almeida Filho /// 34*19096bceSWedson Almeida Filho /// The following is an example of using a condvar with a mutex: 35*19096bceSWedson Almeida Filho /// 36*19096bceSWedson Almeida Filho /// ``` 37*19096bceSWedson Almeida Filho /// use kernel::sync::{CondVar, Mutex}; 38*19096bceSWedson Almeida Filho /// use kernel::{new_condvar, new_mutex}; 39*19096bceSWedson Almeida Filho /// 40*19096bceSWedson Almeida Filho /// #[pin_data] 41*19096bceSWedson Almeida Filho /// pub struct Example { 42*19096bceSWedson Almeida Filho /// #[pin] 43*19096bceSWedson Almeida Filho /// value: Mutex<u32>, 44*19096bceSWedson Almeida Filho /// 45*19096bceSWedson Almeida Filho /// #[pin] 46*19096bceSWedson Almeida Filho /// value_changed: CondVar, 47*19096bceSWedson Almeida Filho /// } 48*19096bceSWedson Almeida Filho /// 49*19096bceSWedson Almeida Filho /// /// Waits for `e.value` to become `v`. 50*19096bceSWedson Almeida Filho /// fn wait_for_value(e: &Example, v: u32) { 51*19096bceSWedson Almeida Filho /// let mut guard = e.value.lock(); 52*19096bceSWedson Almeida Filho /// while *guard != v { 53*19096bceSWedson Almeida Filho /// e.value_changed.wait_uninterruptible(&mut guard); 54*19096bceSWedson Almeida Filho /// } 55*19096bceSWedson Almeida Filho /// } 56*19096bceSWedson Almeida Filho /// 57*19096bceSWedson Almeida Filho /// /// Increments `e.value` and notifies all potential waiters. 58*19096bceSWedson Almeida Filho /// fn increment(e: &Example) { 59*19096bceSWedson Almeida Filho /// *e.value.lock() += 1; 60*19096bceSWedson Almeida Filho /// e.value_changed.notify_all(); 61*19096bceSWedson Almeida Filho /// } 62*19096bceSWedson Almeida Filho /// 63*19096bceSWedson Almeida Filho /// /// Allocates a new boxed `Example`. 64*19096bceSWedson Almeida Filho /// fn new_example() -> Result<Pin<Box<Example>>> { 65*19096bceSWedson Almeida Filho /// Box::pin_init(pin_init!(Example { 66*19096bceSWedson Almeida Filho /// value <- new_mutex!(0), 67*19096bceSWedson Almeida Filho /// value_changed <- new_condvar!(), 68*19096bceSWedson Almeida Filho /// })) 69*19096bceSWedson Almeida Filho /// } 70*19096bceSWedson Almeida Filho /// ``` 71*19096bceSWedson Almeida Filho /// 72*19096bceSWedson Almeida Filho /// [`struct wait_queue_head`]: ../../../include/linux/wait.h 73*19096bceSWedson Almeida Filho #[pin_data] 74*19096bceSWedson Almeida Filho pub struct CondVar { 75*19096bceSWedson Almeida Filho #[pin] 76*19096bceSWedson Almeida Filho pub(crate) wait_list: Opaque<bindings::wait_queue_head>, 77*19096bceSWedson Almeida Filho 78*19096bceSWedson Almeida Filho /// A condvar needs to be pinned because it contains a [`struct list_head`] that is 79*19096bceSWedson Almeida Filho /// self-referential, so it cannot be safely moved once it is initialised. 80*19096bceSWedson Almeida Filho #[pin] 81*19096bceSWedson Almeida Filho _pin: PhantomPinned, 82*19096bceSWedson Almeida Filho } 83*19096bceSWedson Almeida Filho 84*19096bceSWedson Almeida Filho // SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread. 85*19096bceSWedson Almeida Filho #[allow(clippy::non_send_fields_in_send_ty)] 86*19096bceSWedson Almeida Filho unsafe impl Send for CondVar {} 87*19096bceSWedson Almeida Filho 88*19096bceSWedson Almeida Filho // SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads 89*19096bceSWedson Almeida Filho // concurrently. 90*19096bceSWedson Almeida Filho unsafe impl Sync for CondVar {} 91*19096bceSWedson Almeida Filho 92*19096bceSWedson Almeida Filho impl CondVar { 93*19096bceSWedson Almeida Filho /// Constructs a new condvar initialiser. 94*19096bceSWedson Almeida Filho #[allow(clippy::new_ret_no_self)] new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self>95*19096bceSWedson Almeida Filho pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> { 96*19096bceSWedson Almeida Filho pin_init!(Self { 97*19096bceSWedson Almeida Filho _pin: PhantomPinned, 98*19096bceSWedson Almeida Filho // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have 99*19096bceSWedson Almeida Filho // static lifetimes so they live indefinitely. 100*19096bceSWedson Almeida Filho wait_list <- Opaque::ffi_init(|slot| unsafe { 101*19096bceSWedson Almeida Filho bindings::__init_waitqueue_head(slot, name.as_char_ptr(), key.as_ptr()) 102*19096bceSWedson Almeida Filho }), 103*19096bceSWedson Almeida Filho }) 104*19096bceSWedson Almeida Filho } 105*19096bceSWedson Almeida Filho wait_internal<T: ?Sized, B: Backend>(&self, wait_state: u32, guard: &mut Guard<'_, T, B>)106*19096bceSWedson Almeida Filho fn wait_internal<T: ?Sized, B: Backend>(&self, wait_state: u32, guard: &mut Guard<'_, T, B>) { 107*19096bceSWedson Almeida Filho let wait = Opaque::<bindings::wait_queue_entry>::uninit(); 108*19096bceSWedson Almeida Filho 109*19096bceSWedson Almeida Filho // SAFETY: `wait` points to valid memory. 110*19096bceSWedson Almeida Filho unsafe { bindings::init_wait(wait.get()) }; 111*19096bceSWedson Almeida Filho 112*19096bceSWedson Almeida Filho // SAFETY: Both `wait` and `wait_list` point to valid memory. 113*19096bceSWedson Almeida Filho unsafe { 114*19096bceSWedson Almeida Filho bindings::prepare_to_wait_exclusive(self.wait_list.get(), wait.get(), wait_state as _) 115*19096bceSWedson Almeida Filho }; 116*19096bceSWedson Almeida Filho 117*19096bceSWedson Almeida Filho // SAFETY: No arguments, switches to another thread. 118*19096bceSWedson Almeida Filho guard.do_unlocked(|| unsafe { bindings::schedule() }); 119*19096bceSWedson Almeida Filho 120*19096bceSWedson Almeida Filho // SAFETY: Both `wait` and `wait_list` point to valid memory. 121*19096bceSWedson Almeida Filho unsafe { bindings::finish_wait(self.wait_list.get(), wait.get()) }; 122*19096bceSWedson Almeida Filho } 123*19096bceSWedson Almeida Filho 124*19096bceSWedson Almeida Filho /// Releases the lock and waits for a notification in interruptible mode. 125*19096bceSWedson Almeida Filho /// 126*19096bceSWedson Almeida Filho /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the 127*19096bceSWedson Almeida Filho /// thread to sleep, reacquiring the lock on wake up. It wakes up when notified by 128*19096bceSWedson Almeida Filho /// [`CondVar::notify_one`] or [`CondVar::notify_all`], or when the thread receives a signal. 129*19096bceSWedson Almeida Filho /// It may also wake up spuriously. 130*19096bceSWedson Almeida Filho /// 131*19096bceSWedson Almeida Filho /// Returns whether there is a signal pending. 132*19096bceSWedson Almeida Filho #[must_use = "wait returns if a signal is pending, so the caller must check the return value"] wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool133*19096bceSWedson Almeida Filho pub fn wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool { 134*19096bceSWedson Almeida Filho self.wait_internal(bindings::TASK_INTERRUPTIBLE, guard); 135*19096bceSWedson Almeida Filho crate::current!().signal_pending() 136*19096bceSWedson Almeida Filho } 137*19096bceSWedson Almeida Filho 138*19096bceSWedson Almeida Filho /// Releases the lock and waits for a notification in uninterruptible mode. 139*19096bceSWedson Almeida Filho /// 140*19096bceSWedson Almeida Filho /// Similar to [`CondVar::wait`], except that the wait is not interruptible. That is, the 141*19096bceSWedson Almeida Filho /// thread won't wake up due to signals. It may, however, wake up supirously. wait_uninterruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>)142*19096bceSWedson Almeida Filho pub fn wait_uninterruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) { 143*19096bceSWedson Almeida Filho self.wait_internal(bindings::TASK_UNINTERRUPTIBLE, guard) 144*19096bceSWedson Almeida Filho } 145*19096bceSWedson Almeida Filho 146*19096bceSWedson Almeida Filho /// Calls the kernel function to notify the appropriate number of threads with the given flags. notify(&self, count: i32, flags: u32)147*19096bceSWedson Almeida Filho fn notify(&self, count: i32, flags: u32) { 148*19096bceSWedson Almeida Filho // SAFETY: `wait_list` points to valid memory. 149*19096bceSWedson Almeida Filho unsafe { 150*19096bceSWedson Almeida Filho bindings::__wake_up( 151*19096bceSWedson Almeida Filho self.wait_list.get(), 152*19096bceSWedson Almeida Filho bindings::TASK_NORMAL, 153*19096bceSWedson Almeida Filho count, 154*19096bceSWedson Almeida Filho flags as _, 155*19096bceSWedson Almeida Filho ) 156*19096bceSWedson Almeida Filho }; 157*19096bceSWedson Almeida Filho } 158*19096bceSWedson Almeida Filho 159*19096bceSWedson Almeida Filho /// Wakes a single waiter up, if any. 160*19096bceSWedson Almeida Filho /// 161*19096bceSWedson Almeida Filho /// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost 162*19096bceSWedson Almeida Filho /// completely (as opposed to automatically waking up the next waiter). notify_one(&self)163*19096bceSWedson Almeida Filho pub fn notify_one(&self) { 164*19096bceSWedson Almeida Filho self.notify(1, 0); 165*19096bceSWedson Almeida Filho } 166*19096bceSWedson Almeida Filho 167*19096bceSWedson Almeida Filho /// Wakes all waiters up, if any. 168*19096bceSWedson Almeida Filho /// 169*19096bceSWedson Almeida Filho /// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost 170*19096bceSWedson Almeida Filho /// completely (as opposed to automatically waking up the next waiter). notify_all(&self)171*19096bceSWedson Almeida Filho pub fn notify_all(&self) { 172*19096bceSWedson Almeida Filho self.notify(0, 0); 173*19096bceSWedson Almeida Filho } 174*19096bceSWedson Almeida Filho } 175