mirror of
https://github.com/torvalds/linux.git
synced 2025-11-01 17:18:25 +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,
|
|
},
|
|
}
|