mirror of
https://github.com/torvalds/linux.git
synced 2025-08-17 15:11:34 +02:00

Toolchain and infrastructure: - Extract the 'pin-init' API from the 'kernel' crate and make it into a standalone crate. In order to do this, the contents are rearranged so that they can easily be kept in sync with the version maintained out-of-tree that other projects have started to use too (or plan to, like QEMU). This will reduce the maintenance burden for Benno, who will now have his own sub-tree, and will simplify future expected changes like the move to use 'syn' to simplify the implementation. - Add '#[test]'-like support based on KUnit. We already had doctests support based on KUnit, which takes the examples in our Rust documentation and runs them under KUnit. Now, we are adding the beginning of the support for "normal" tests, similar to those the '#[test]' tests in userspace Rust. For instance: #[kunit_tests(my_suite)] mod tests { #[test] fn my_test() { assert_eq!(1 + 1, 2); } } Unlike with doctests, the 'assert*!'s do not map to the KUnit assertion APIs yet. - Check Rust signatures at compile time for functions called from C by name. In particular, introduce a new '#[export]' macro that can be placed in the Rust function definition. It will ensure that the function declaration on the C side matches the signature on the Rust function: #[export] pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize { // ... } The macro essentially forces the compiler to compare the types of the actual Rust function and the 'bindgen'-processed C signature. These cases are rare so far. In the future, we may consider introducing another tool, 'cbindgen', to generate C headers automatically. Even then, having these functions explicitly marked may be a good idea anyway. - Enable the 'raw_ref_op' Rust feature: it is already stable, and allows us to use the new '&raw' syntax, avoiding a couple macros. After everyone has migrated, we will disallow the macros. - Pass the correct target to 'bindgen' on Usermode Linux. - Fix 'rusttest' build in macOS. 'kernel' crate: - New 'hrtimer' module: add support for setting up intrusive timers without allocating when starting the timer. Add support for 'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer types for use with timer callbacks. Add support for setting clock source and timer mode. - New 'dma' module: add a simple DMA coherent allocator abstraction and a test sample driver. - 'list' module: make the linked list 'Cursor' point between elements, rather than at an element, which is more convenient to us and allows for cursors to empty lists; and document it with examples of how to perform common operations with the provided methods. - 'str' module: implement a few traits for 'BStr' as well as the 'strip_prefix()' method. - 'sync' module: add 'Arc::as_ptr'. - 'alloc' module: add 'Box::into_pin'. - 'error' module: extend the 'Result' documentation, including a few examples on different ways of handling errors, a warning about using methods that may panic, and links to external documentation. 'macros' crate: - 'module' macro: add the 'authors' key to support multiple authors. The original key will be kept until everyone has migrated. Documentation: - Add error handling sections. MAINTAINERS: - Add Danilo Krummrich as reviewer of the Rust "subsystem". - Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has its own sub-tree. - Add sub-tree for 'RUST [ALLOC]'. - Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with Abdiel Janulgue as primary maintainer. It will go through the sub-tree of the 'RUST [ALLOC]' entry. - Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as maintainer. It has its own sub-tree. And a few other cleanups and improvements. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmfpQgAACgkQGXyLc2ht IW35CQ//VOIFKtG6qgHVMIxrmpT7YFsrAU41h+cHT2lzy5KiTqSYlCgd18SJ+Iyy vi1ylfdyqOpH5EoO+opPN2H4E+VUlRJg7BkZrT4p1lgGDEKg1mtR/825TxquLNFM A653f3FvK/scMb6X43kWNKGK/jnxlfxBGmUwIY4/p7+adIuZzXnNbPkV9XYGLx3r 8KIBKJ9gM52eXoCoF8XJpg6Vg/0rYWIet32OzYF0PvzSAOqUlH4keu15jeUo+59V tgCzAkc2yV3oSo721KYlpPeCPKI5iVCzIcwT0n8fqraXtgGnaFPe5XF16U9Qvrjv vRp5/dePAHwsOcj5ErzOgLMqGa1sqY76lxDI05PNcBJ8fBAhNEV/rpCTXs/wRagQ xUZOdsQyEn0V/BOtV+dnwu410dElEeJdOAeojSYFm1gUay43a0e6yIboxn3Ylnfx 8jONSokZ/UFHX3wOFNqHeXsY+REB8Qq8OZXjNBZVFpKHNsICWA0G3BcCRnB1815k 0v7seSdrST78EJ/A5nM0a9gghuLzYgAN04SDx0FzKjb2mHs3PiVfXDvrNMCJ0pBW zbF9RlvszKZStY5tpxdZ5Zh+f7rfYcnJHYhNpoP7DJr136iWP+NnHbk1lK6+o4WY lPVdMMgUSUlEXIHgK2ebcb/I1KBrDYiPktmvKAFLrH3qVzhkLAU= =PCxf -----END PGP SIGNATURE----- Merge tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Extract the 'pin-init' API from the 'kernel' crate and make it into a standalone crate. In order to do this, the contents are rearranged so that they can easily be kept in sync with the version maintained out-of-tree that other projects have started to use too (or plan to, like QEMU). This will reduce the maintenance burden for Benno, who will now have his own sub-tree, and will simplify future expected changes like the move to use 'syn' to simplify the implementation. - Add '#[test]'-like support based on KUnit. We already had doctests support based on KUnit, which takes the examples in our Rust documentation and runs them under KUnit. Now, we are adding the beginning of the support for "normal" tests, similar to those the '#[test]' tests in userspace Rust. For instance: #[kunit_tests(my_suite)] mod tests { #[test] fn my_test() { assert_eq!(1 + 1, 2); } } Unlike with doctests, the 'assert*!'s do not map to the KUnit assertion APIs yet. - Check Rust signatures at compile time for functions called from C by name. In particular, introduce a new '#[export]' macro that can be placed in the Rust function definition. It will ensure that the function declaration on the C side matches the signature on the Rust function: #[export] pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize { // ... } The macro essentially forces the compiler to compare the types of the actual Rust function and the 'bindgen'-processed C signature. These cases are rare so far. In the future, we may consider introducing another tool, 'cbindgen', to generate C headers automatically. Even then, having these functions explicitly marked may be a good idea anyway. - Enable the 'raw_ref_op' Rust feature: it is already stable, and allows us to use the new '&raw' syntax, avoiding a couple macros. After everyone has migrated, we will disallow the macros. - Pass the correct target to 'bindgen' on Usermode Linux. - Fix 'rusttest' build in macOS. 'kernel' crate: - New 'hrtimer' module: add support for setting up intrusive timers without allocating when starting the timer. Add support for 'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer types for use with timer callbacks. Add support for setting clock source and timer mode. - New 'dma' module: add a simple DMA coherent allocator abstraction and a test sample driver. - 'list' module: make the linked list 'Cursor' point between elements, rather than at an element, which is more convenient to us and allows for cursors to empty lists; and document it with examples of how to perform common operations with the provided methods. - 'str' module: implement a few traits for 'BStr' as well as the 'strip_prefix()' method. - 'sync' module: add 'Arc::as_ptr'. - 'alloc' module: add 'Box::into_pin'. - 'error' module: extend the 'Result' documentation, including a few examples on different ways of handling errors, a warning about using methods that may panic, and links to external documentation. 'macros' crate: - 'module' macro: add the 'authors' key to support multiple authors. The original key will be kept until everyone has migrated. Documentation: - Add error handling sections. MAINTAINERS: - Add Danilo Krummrich as reviewer of the Rust "subsystem". - Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has its own sub-tree. - Add sub-tree for 'RUST [ALLOC]'. - Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with Abdiel Janulgue as primary maintainer. It will go through the sub-tree of the 'RUST [ALLOC]' entry. - Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as maintainer. It has its own sub-tree. And a few other cleanups and improvements" * tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (71 commits) rust: dma: add `Send` implementation for `CoherentAllocation` rust: macros: fix `make rusttest` build on macOS rust: block: refactor to use `&raw mut` rust: enable `raw_ref_op` feature rust: uaccess: name the correct function rust: rbtree: fix comments referring to Box instead of KBox rust: hrtimer: add maintainer entry rust: hrtimer: add clocksource selection through `ClockId` rust: hrtimer: add `HrTimerMode` rust: hrtimer: implement `HrTimerPointer` for `Pin<Box<T>>` rust: alloc: add `Box::into_pin` rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&mut T>` rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&T>` rust: hrtimer: add `hrtimer::ScopedHrTimerPointer` rust: hrtimer: add `UnsafeHrTimerPointer` rust: hrtimer: allow timer restart from timer handler rust: str: implement `strip_prefix` for `BStr` rust: str: implement `AsRef<BStr>` for `[u8]` and `BStr` rust: str: implement `Index` for `BStr` rust: str: implement `PartialEq` for `BStr` ...
255 lines
9.3 KiB
Rust
255 lines
9.3 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
//! A condition variable.
|
|
//!
|
|
//! This module allows Rust code to use the kernel's [`struct wait_queue_head`] as a condition
|
|
//! variable.
|
|
|
|
use super::{lock::Backend, lock::Guard, LockClassKey};
|
|
use crate::{
|
|
ffi::{c_int, c_long},
|
|
str::CStr,
|
|
task::{
|
|
MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE,
|
|
},
|
|
time::Jiffies,
|
|
types::Opaque,
|
|
};
|
|
use core::{marker::PhantomPinned, pin::Pin, ptr};
|
|
use pin_init::{pin_data, pin_init, PinInit};
|
|
|
|
/// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
|
|
#[macro_export]
|
|
macro_rules! new_condvar {
|
|
($($name:literal)?) => {
|
|
$crate::sync::CondVar::new($crate::optional_name!($($name)?), $crate::static_lock_class!())
|
|
};
|
|
}
|
|
pub use new_condvar;
|
|
|
|
/// A conditional variable.
|
|
///
|
|
/// Exposes the kernel's [`struct wait_queue_head`] as a condition variable. It allows the caller to
|
|
/// atomically release the given lock and go to sleep. It reacquires the lock when it wakes up. And
|
|
/// it wakes up when notified by another thread (via [`CondVar::notify_one`] or
|
|
/// [`CondVar::notify_all`]) or because the thread received a signal. It may also wake up
|
|
/// spuriously.
|
|
///
|
|
/// Instances of [`CondVar`] need a lock class and to be pinned. The recommended way to create such
|
|
/// instances is with the [`pin_init`](crate::pin_init!) and [`new_condvar`] macros.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// The following is an example of using a condvar with a mutex:
|
|
///
|
|
/// ```
|
|
/// use kernel::sync::{new_condvar, new_mutex, CondVar, Mutex};
|
|
///
|
|
/// #[pin_data]
|
|
/// pub struct Example {
|
|
/// #[pin]
|
|
/// value: Mutex<u32>,
|
|
///
|
|
/// #[pin]
|
|
/// value_changed: CondVar,
|
|
/// }
|
|
///
|
|
/// /// Waits for `e.value` to become `v`.
|
|
/// fn wait_for_value(e: &Example, v: u32) {
|
|
/// let mut guard = e.value.lock();
|
|
/// while *guard != v {
|
|
/// e.value_changed.wait(&mut guard);
|
|
/// }
|
|
/// }
|
|
///
|
|
/// /// Increments `e.value` and notifies all potential waiters.
|
|
/// fn increment(e: &Example) {
|
|
/// *e.value.lock() += 1;
|
|
/// e.value_changed.notify_all();
|
|
/// }
|
|
///
|
|
/// /// Allocates a new boxed `Example`.
|
|
/// fn new_example() -> Result<Pin<KBox<Example>>> {
|
|
/// KBox::pin_init(pin_init!(Example {
|
|
/// value <- new_mutex!(0),
|
|
/// value_changed <- new_condvar!(),
|
|
/// }), GFP_KERNEL)
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// [`struct wait_queue_head`]: srctree/include/linux/wait.h
|
|
#[pin_data]
|
|
pub struct CondVar {
|
|
#[pin]
|
|
pub(crate) wait_queue_head: Opaque<bindings::wait_queue_head>,
|
|
|
|
/// A condvar needs to be pinned because it contains a [`struct list_head`] that is
|
|
/// self-referential, so it cannot be safely moved once it is initialised.
|
|
///
|
|
/// [`struct list_head`]: srctree/include/linux/types.h
|
|
#[pin]
|
|
_pin: PhantomPinned,
|
|
}
|
|
|
|
// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread.
|
|
unsafe impl Send for CondVar {}
|
|
|
|
// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads
|
|
// concurrently.
|
|
unsafe impl Sync for CondVar {}
|
|
|
|
impl CondVar {
|
|
/// Constructs a new condvar initialiser.
|
|
pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
|
|
pin_init!(Self {
|
|
_pin: PhantomPinned,
|
|
// SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
|
|
// static lifetimes so they live indefinitely.
|
|
wait_queue_head <- Opaque::ffi_init(|slot| unsafe {
|
|
bindings::__init_waitqueue_head(slot, name.as_char_ptr(), key.as_ptr())
|
|
}),
|
|
})
|
|
}
|
|
|
|
fn wait_internal<T: ?Sized, B: Backend>(
|
|
&self,
|
|
wait_state: c_int,
|
|
guard: &mut Guard<'_, T, B>,
|
|
timeout_in_jiffies: c_long,
|
|
) -> c_long {
|
|
let wait = Opaque::<bindings::wait_queue_entry>::uninit();
|
|
|
|
// SAFETY: `wait` points to valid memory.
|
|
unsafe { bindings::init_wait(wait.get()) };
|
|
|
|
// SAFETY: Both `wait` and `wait_queue_head` point to valid memory.
|
|
unsafe {
|
|
bindings::prepare_to_wait_exclusive(self.wait_queue_head.get(), wait.get(), wait_state)
|
|
};
|
|
|
|
// SAFETY: Switches to another thread. The timeout can be any number.
|
|
let ret = guard.do_unlocked(|| unsafe { bindings::schedule_timeout(timeout_in_jiffies) });
|
|
|
|
// SAFETY: Both `wait` and `wait_queue_head` point to valid memory.
|
|
unsafe { bindings::finish_wait(self.wait_queue_head.get(), wait.get()) };
|
|
|
|
ret
|
|
}
|
|
|
|
/// Releases the lock and waits for a notification in uninterruptible mode.
|
|
///
|
|
/// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
|
|
/// thread to sleep, reacquiring the lock on wake up. It wakes up when notified by
|
|
/// [`CondVar::notify_one`] or [`CondVar::notify_all`]. Note that it may also wake up
|
|
/// spuriously.
|
|
pub fn wait<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) {
|
|
self.wait_internal(TASK_UNINTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
|
|
}
|
|
|
|
/// Releases the lock and waits for a notification in interruptible mode.
|
|
///
|
|
/// Similar to [`CondVar::wait`], except that the wait is interruptible. That is, the thread may
|
|
/// wake up due to signals. It may also wake up spuriously.
|
|
///
|
|
/// Returns whether there is a signal pending.
|
|
#[must_use = "wait_interruptible returns if a signal is pending, so the caller must check the return value"]
|
|
pub fn wait_interruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T, B>) -> bool {
|
|
self.wait_internal(TASK_INTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
|
|
crate::current!().signal_pending()
|
|
}
|
|
|
|
/// Releases the lock and waits for a notification in interruptible and freezable mode.
|
|
///
|
|
/// The process is allowed to be frozen during this sleep. No lock should be held when calling
|
|
/// this function, and there is a lockdep assertion for this. Freezing a task that holds a lock
|
|
/// can trivially deadlock vs another task that needs that lock to complete before it too can
|
|
/// hit freezable.
|
|
#[must_use = "wait_interruptible_freezable returns if a signal is pending, so the caller must check the return value"]
|
|
pub fn wait_interruptible_freezable<T: ?Sized, B: Backend>(
|
|
&self,
|
|
guard: &mut Guard<'_, T, B>,
|
|
) -> bool {
|
|
self.wait_internal(
|
|
TASK_INTERRUPTIBLE | TASK_FREEZABLE,
|
|
guard,
|
|
MAX_SCHEDULE_TIMEOUT,
|
|
);
|
|
crate::current!().signal_pending()
|
|
}
|
|
|
|
/// Releases the lock and waits for a notification in interruptible mode.
|
|
///
|
|
/// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
|
|
/// thread to sleep. It wakes up when notified by [`CondVar::notify_one`] or
|
|
/// [`CondVar::notify_all`], or when a timeout occurs, or when the thread receives a signal.
|
|
#[must_use = "wait_interruptible_timeout returns if a signal is pending, so the caller must check the return value"]
|
|
pub fn wait_interruptible_timeout<T: ?Sized, B: Backend>(
|
|
&self,
|
|
guard: &mut Guard<'_, T, B>,
|
|
jiffies: Jiffies,
|
|
) -> CondVarTimeoutResult {
|
|
let jiffies = jiffies.try_into().unwrap_or(MAX_SCHEDULE_TIMEOUT);
|
|
let res = self.wait_internal(TASK_INTERRUPTIBLE, guard, jiffies);
|
|
|
|
match (res as Jiffies, crate::current!().signal_pending()) {
|
|
(jiffies, true) => CondVarTimeoutResult::Signal { jiffies },
|
|
(0, false) => CondVarTimeoutResult::Timeout,
|
|
(jiffies, false) => CondVarTimeoutResult::Woken { jiffies },
|
|
}
|
|
}
|
|
|
|
/// Calls the kernel function to notify the appropriate number of threads.
|
|
fn notify(&self, count: c_int) {
|
|
// SAFETY: `wait_queue_head` points to valid memory.
|
|
unsafe {
|
|
bindings::__wake_up(
|
|
self.wait_queue_head.get(),
|
|
TASK_NORMAL,
|
|
count,
|
|
ptr::null_mut(),
|
|
)
|
|
};
|
|
}
|
|
|
|
/// Calls the kernel function to notify one thread synchronously.
|
|
///
|
|
/// This method behaves like `notify_one`, except that it hints to the scheduler that the
|
|
/// current thread is about to go to sleep, so it should schedule the target thread on the same
|
|
/// CPU.
|
|
pub fn notify_sync(&self) {
|
|
// SAFETY: `wait_queue_head` points to valid memory.
|
|
unsafe { bindings::__wake_up_sync(self.wait_queue_head.get(), TASK_NORMAL) };
|
|
}
|
|
|
|
/// Wakes a single waiter up, if any.
|
|
///
|
|
/// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost
|
|
/// completely (as opposed to automatically waking up the next waiter).
|
|
pub fn notify_one(&self) {
|
|
self.notify(1);
|
|
}
|
|
|
|
/// Wakes all waiters up, if any.
|
|
///
|
|
/// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost
|
|
/// completely (as opposed to automatically waking up the next waiter).
|
|
pub fn notify_all(&self) {
|
|
self.notify(0);
|
|
}
|
|
}
|
|
|
|
/// The return type of `wait_timeout`.
|
|
pub enum CondVarTimeoutResult {
|
|
/// The timeout was reached.
|
|
Timeout,
|
|
/// Somebody woke us up.
|
|
Woken {
|
|
/// Remaining sleep duration.
|
|
jiffies: Jiffies,
|
|
},
|
|
/// A signal occurred.
|
|
Signal {
|
|
/// Remaining sleep duration.
|
|
jiffies: Jiffies,
|
|
},
|
|
}
|