mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
rust: sync: update integer types in CondVar
Reduce the chances of compilation failures due to integer type mismatches in `CondVar`. When an integer is defined using a #define in C, bindgen doesn't know which integer type it is supposed to be, so it will just use `u32` by default (if it fits in an u32). Whenever the right type is something else, we insert a cast in Rust. However, this means that the code has a lot of extra casts, and sometimes the code will be missing casts if u32 happens to be correct on the developer's machine, even though the type might be something else on a different platform. This patch updates all uses of such constants in `rust/kernel/sync/condvar.rs` to use constants defined with the right type. This allows us to remove various unnecessary casts, while also future-proofing for the case where `unsigned int != u32` (even though that is unlikely to ever happen in the kernel). I wrote this patch at the suggestion of Benno in [1]. Link: https://lore.kernel.org/all/nAEg-6vbtX72ZY3oirDhrSEf06TBWmMiTt73EklMzEAzN4FD4mF3TPEyAOxBZgZtjzoiaBYtYr3s8sa9wp1uYH9vEWRf2M-Lf4I0BY9rAgk=@proton.me/ [1] Suggested-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Tiago Lam <tiagolam@gmail.com> Reviewed-by: Boqun Feng <boqun.feng@gmail.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240108-rb-new-condvar-methods-v4-4-88e0c871cc05@google.com [ Added note on the unlikeliness of `sizeof(int)` changing. ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
e7b9b1ff1d
commit
f090f0d0ee
@ -7,11 +7,17 @@
|
||||
|
||||
use super::{lock::Backend, lock::Guard, LockClassKey};
|
||||
use crate::{
|
||||
bindings, init::PinInit, pin_init, str::CStr, task::MAX_SCHEDULE_TIMEOUT, time::Jiffies,
|
||||
bindings,
|
||||
init::PinInit,
|
||||
pin_init,
|
||||
str::CStr,
|
||||
task::{MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE},
|
||||
time::Jiffies,
|
||||
types::Opaque,
|
||||
};
|
||||
use core::ffi::c_long;
|
||||
use core::ffi::{c_int, c_long};
|
||||
use core::marker::PhantomPinned;
|
||||
use core::ptr;
|
||||
use macros::pin_data;
|
||||
|
||||
/// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
|
||||
@ -108,7 +114,7 @@ impl CondVar {
|
||||
|
||||
fn wait_internal<T: ?Sized, B: Backend>(
|
||||
&self,
|
||||
wait_state: u32,
|
||||
wait_state: c_int,
|
||||
guard: &mut Guard<'_, T, B>,
|
||||
timeout_in_jiffies: c_long,
|
||||
) -> c_long {
|
||||
@ -119,11 +125,7 @@ impl CondVar {
|
||||
|
||||
// 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 as _,
|
||||
)
|
||||
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.
|
||||
@ -142,7 +144,7 @@ impl CondVar {
|
||||
/// [`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(bindings::TASK_UNINTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
|
||||
self.wait_internal(TASK_UNINTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
|
||||
}
|
||||
|
||||
/// Releases the lock and waits for a notification in interruptible mode.
|
||||
@ -153,7 +155,7 @@ impl CondVar {
|
||||
/// 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(bindings::TASK_INTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
|
||||
self.wait_internal(TASK_INTERRUPTIBLE, guard, MAX_SCHEDULE_TIMEOUT);
|
||||
crate::current!().signal_pending()
|
||||
}
|
||||
|
||||
@ -169,7 +171,7 @@ impl CondVar {
|
||||
jiffies: Jiffies,
|
||||
) -> CondVarTimeoutResult {
|
||||
let jiffies = jiffies.try_into().unwrap_or(MAX_SCHEDULE_TIMEOUT);
|
||||
let res = self.wait_internal(bindings::TASK_INTERRUPTIBLE, guard, jiffies);
|
||||
let res = self.wait_internal(TASK_INTERRUPTIBLE, guard, jiffies);
|
||||
|
||||
match (res as Jiffies, crate::current!().signal_pending()) {
|
||||
(jiffies, true) => CondVarTimeoutResult::Signal { jiffies },
|
||||
@ -178,15 +180,15 @@ impl CondVar {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the kernel function to notify the appropriate number of threads with the given flags.
|
||||
fn notify(&self, count: i32, flags: u32) {
|
||||
/// 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(),
|
||||
bindings::TASK_NORMAL,
|
||||
TASK_NORMAL,
|
||||
count,
|
||||
flags as _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
}
|
||||
@ -198,7 +200,7 @@ impl CondVar {
|
||||
/// CPU.
|
||||
pub fn notify_sync(&self) {
|
||||
// SAFETY: `wait_queue_head` points to valid memory.
|
||||
unsafe { bindings::__wake_up_sync(self.wait_queue_head.get(), bindings::TASK_NORMAL) };
|
||||
unsafe { bindings::__wake_up_sync(self.wait_queue_head.get(), TASK_NORMAL) };
|
||||
}
|
||||
|
||||
/// Wakes a single waiter up, if any.
|
||||
@ -206,7 +208,7 @@ impl CondVar {
|
||||
/// 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, 0);
|
||||
self.notify(1);
|
||||
}
|
||||
|
||||
/// Wakes all waiters up, if any.
|
||||
@ -214,7 +216,7 @@ impl CondVar {
|
||||
/// 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, 0);
|
||||
self.notify(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,24 @@
|
||||
//! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
|
||||
|
||||
use crate::{bindings, types::Opaque};
|
||||
use core::{ffi::c_long, marker::PhantomData, ops::Deref, ptr};
|
||||
use core::{
|
||||
ffi::{c_int, c_long, c_uint},
|
||||
marker::PhantomData,
|
||||
ops::Deref,
|
||||
ptr,
|
||||
};
|
||||
|
||||
/// A sentinel value used for infinite timeouts.
|
||||
pub const MAX_SCHEDULE_TIMEOUT: c_long = c_long::MAX;
|
||||
|
||||
/// Bitmask for tasks that are sleeping in an interruptible state.
|
||||
pub const TASK_INTERRUPTIBLE: c_int = bindings::TASK_INTERRUPTIBLE as c_int;
|
||||
/// Bitmask for tasks that are sleeping in an uninterruptible state.
|
||||
pub const TASK_UNINTERRUPTIBLE: c_int = bindings::TASK_UNINTERRUPTIBLE as c_int;
|
||||
/// Convenience constant for waking up tasks regardless of whether they are in interruptible or
|
||||
/// uninterruptible sleep.
|
||||
pub const TASK_NORMAL: c_uint = bindings::TASK_NORMAL as c_uint;
|
||||
|
||||
/// Returns the currently running task.
|
||||
#[macro_export]
|
||||
macro_rules! current {
|
||||
|
Loading…
Reference in New Issue
Block a user