Skip to content

Commit 9695c1e

Browse files
Darksonnfbq
authored andcommitted
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> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240628-alice-file-v7-1-4d701f6335f3@google.com
1 parent 4aa3244 commit 9695c1e

File tree

3 files changed

+33
-8
lines changed

3 files changed

+33
-8
lines changed

rust/kernel/sync/lock.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
//! spinlocks, raw spinlocks) to be provided with minimal effort.
77
88
use super::LockClassKey;
9-
use crate::{init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard};
10-
use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned};
9+
use crate::{
10+
init::PinInit,
11+
pin_init,
12+
str::CStr,
13+
types::{NotThreadSafe, Opaque, ScopeGuard},
14+
};
15+
use core::{cell::UnsafeCell, marker::PhantomPinned};
1116
use macros::pin_data;
1217

1318
pub mod mutex;
@@ -139,7 +144,7 @@ impl<T: ?Sized, B: Backend> Lock<T, B> {
139144
pub struct Guard<'a, T: ?Sized, B: Backend> {
140145
pub(crate) lock: &'a Lock<T, B>,
141146
pub(crate) state: B::GuardState,
142-
_not_send: PhantomData<*mut ()>,
147+
_not_send: NotThreadSafe,
143148
}
144149

145150
// 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> {
191196
Self {
192197
lock,
193198
state,
194-
_not_send: PhantomData,
199+
_not_send: NotThreadSafe,
195200
}
196201
}
197202
}

rust/kernel/task.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
//!
55
//! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
66
7-
use crate::types::Opaque;
7+
use crate::{
8+
bindings,
9+
types::{NotThreadSafe, Opaque},
10+
};
811
use core::{
912
ffi::{c_int, c_long, c_uint},
10-
marker::PhantomData,
1113
ops::Deref,
1214
ptr,
1315
};
@@ -106,7 +108,7 @@ impl Task {
106108
pub unsafe fn current() -> impl Deref<Target = Task> {
107109
struct TaskRef<'a> {
108110
task: &'a Task,
109-
_not_send: PhantomData<*mut ()>,
111+
_not_send: NotThreadSafe,
110112
}
111113

112114
impl Deref for TaskRef<'_> {
@@ -125,7 +127,7 @@ impl Task {
125127
// that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
126128
// (where it could potentially outlive the caller).
127129
task: unsafe { &*ptr.cast() },
128-
_not_send: PhantomData,
130+
_not_send: NotThreadSafe,
129131
}
130132
}
131133

rust/kernel/types.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,21 @@ unsafe impl AsBytes for str {}
518518
// does not have any uninitialized portions either.
519519
unsafe impl<T: AsBytes> AsBytes for [T] {}
520520
unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
521+
522+
/// Zero-sized type to mark types not [`Send`].
523+
///
524+
/// Add this type as a field to your struct if your type should not be sent to a different task.
525+
/// Since [`Send`] is an auto trait, adding a single field that is `!Send` will ensure that the
526+
/// whole type is `!Send`.
527+
///
528+
/// If a type is `!Send` it is impossible to give control over an instance of the type to another
529+
/// task. This is useful to include in types that store or reference task-local information. A file
530+
/// descriptor is an example of such task-local information.
531+
pub type NotThreadSafe = PhantomData<*mut ()>;
532+
533+
/// Used to construct instances of type [`NotThreadSafe`] similar to how `PhantomData` is
534+
/// constructed.
535+
///
536+
/// [`NotThreadSafe`]: type@NotThreadSafe
537+
#[allow(non_upper_case_globals)]
538+
pub const NotThreadSafe: NotThreadSafe = PhantomData;

0 commit comments

Comments
 (0)