mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
rust: types: add NotThreadSafe
This introduces a new marker type for types that shouldn't be thread safe. By adding a field of this type to a struct, it becomes non-Send and non-Sync, which means that it cannot be accessed in any way from threads other than the one it was created on. This is useful for APIs that require globals such as `current` to remain constant while the value exists. We update two existing users in the Kernel to use this helper: * `Task::current()` - moving the return type of this value to a different thread would not be safe as you can no longer be guaranteed that the `current` pointer remains valid. * Lock guards. Mutexes and spinlocks should be unlocked on the same thread as where they were locked, so we enforce this using the Send trait. There are also additional users in later patches of this patchset. See [1] and [2] for the discussion that led to the introduction of this patch. Link: https://lore.kernel.org/all/nFDPJFnzE9Q5cqY7FwSMByRH2OAn_BpI4H53NQfWIlN6I2qfmAqnkp2wRqn0XjMO65OyZY4h6P4K2nAGKJpAOSzksYXaiAK_FoH_8QbgBI4=@proton.me/ [1] Link: https://lore.kernel.org/all/nFDPJFnzE9Q5cqY7FwSMByRH2OAn_BpI4H53NQfWIlN6I2qfmAqnkp2wRqn0XjMO65OyZY4h6P4K2nAGKJpAOSzksYXaiAK_FoH_8QbgBI4=@proton.me/ [2] Suggested-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Trevor Gross <tmgross@umich.edu> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Reviewed-by: Björn Roy Baron <bjorn3_gh@protonmail.com> Reviewed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240915-alice-file-v10-1-88484f7a3dcf@google.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
d077242d68
commit
e7572e5dea
@ -6,8 +6,13 @@
|
|||||||
//! spinlocks, raw spinlocks) to be provided with minimal effort.
|
//! spinlocks, raw spinlocks) to be provided with minimal effort.
|
||||||
|
|
||||||
use super::LockClassKey;
|
use super::LockClassKey;
|
||||||
use crate::{init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard};
|
use crate::{
|
||||||
use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned};
|
init::PinInit,
|
||||||
|
pin_init,
|
||||||
|
str::CStr,
|
||||||
|
types::{NotThreadSafe, Opaque, ScopeGuard},
|
||||||
|
};
|
||||||
|
use core::{cell::UnsafeCell, marker::PhantomPinned};
|
||||||
use macros::pin_data;
|
use macros::pin_data;
|
||||||
|
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
@ -139,7 +144,7 @@ impl<T: ?Sized, B: Backend> Lock<T, B> {
|
|||||||
pub struct Guard<'a, T: ?Sized, B: Backend> {
|
pub struct Guard<'a, T: ?Sized, B: Backend> {
|
||||||
pub(crate) lock: &'a Lock<T, B>,
|
pub(crate) lock: &'a Lock<T, B>,
|
||||||
pub(crate) state: B::GuardState,
|
pub(crate) state: B::GuardState,
|
||||||
_not_send: PhantomData<*mut ()>,
|
_not_send: NotThreadSafe,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: `Guard` is sync when the data protected by the lock is also sync.
|
// SAFETY: `Guard` is sync when the data protected by the lock is also sync.
|
||||||
@ -191,7 +196,7 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
|
|||||||
Self {
|
Self {
|
||||||
lock,
|
lock,
|
||||||
state,
|
state,
|
||||||
_not_send: PhantomData,
|
_not_send: NotThreadSafe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
//!
|
//!
|
||||||
//! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
|
//! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
|
||||||
|
|
||||||
use crate::types::Opaque;
|
use crate::{
|
||||||
|
bindings,
|
||||||
|
types::{NotThreadSafe, Opaque},
|
||||||
|
};
|
||||||
use core::{
|
use core::{
|
||||||
ffi::{c_int, c_long, c_uint},
|
ffi::{c_int, c_long, c_uint},
|
||||||
marker::PhantomData,
|
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
ptr,
|
ptr,
|
||||||
};
|
};
|
||||||
@ -106,7 +108,7 @@ impl Task {
|
|||||||
pub unsafe fn current() -> impl Deref<Target = Task> {
|
pub unsafe fn current() -> impl Deref<Target = Task> {
|
||||||
struct TaskRef<'a> {
|
struct TaskRef<'a> {
|
||||||
task: &'a Task,
|
task: &'a Task,
|
||||||
_not_send: PhantomData<*mut ()>,
|
_not_send: NotThreadSafe,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for TaskRef<'_> {
|
impl Deref for TaskRef<'_> {
|
||||||
@ -125,7 +127,7 @@ impl Task {
|
|||||||
// that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
|
// that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
|
||||||
// (where it could potentially outlive the caller).
|
// (where it could potentially outlive the caller).
|
||||||
task: unsafe { &*ptr.cast() },
|
task: unsafe { &*ptr.cast() },
|
||||||
_not_send: PhantomData,
|
_not_send: NotThreadSafe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,3 +532,24 @@ unsafe impl AsBytes for str {}
|
|||||||
// does not have any uninitialized portions either.
|
// does not have any uninitialized portions either.
|
||||||
unsafe impl<T: AsBytes> AsBytes for [T] {}
|
unsafe impl<T: AsBytes> AsBytes for [T] {}
|
||||||
unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
|
unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
|
||||||
|
|
||||||
|
/// Zero-sized type to mark types not [`Send`].
|
||||||
|
///
|
||||||
|
/// Add this type as a field to your struct if your type should not be sent to a different task.
|
||||||
|
/// Since [`Send`] is an auto trait, adding a single field that is `!Send` will ensure that the
|
||||||
|
/// whole type is `!Send`.
|
||||||
|
///
|
||||||
|
/// If a type is `!Send` it is impossible to give control over an instance of the type to another
|
||||||
|
/// task. This is useful to include in types that store or reference task-local information. A file
|
||||||
|
/// descriptor is an example of such task-local information.
|
||||||
|
///
|
||||||
|
/// This type also makes the type `!Sync`, which prevents immutable access to the value from
|
||||||
|
/// several threads in parallel.
|
||||||
|
pub type NotThreadSafe = PhantomData<*mut ()>;
|
||||||
|
|
||||||
|
/// Used to construct instances of type [`NotThreadSafe`] similar to how `PhantomData` is
|
||||||
|
/// constructed.
|
||||||
|
///
|
||||||
|
/// [`NotThreadSafe`]: type@NotThreadSafe
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const NotThreadSafe: NotThreadSafe = PhantomData;
|
||||||
|
Loading…
Reference in New Issue
Block a user