Skip to content

Commit 4b9a68f

Browse files
committed
rust: add support for static synchronisation primitives
This allows drivers to declare global shared variables (`static`) that can be mutated when the synchronisation primitive is held. Although we want to discourage the use of globals, some drivers still need them. For example, a driver that needs to allocate an id to each instance of a device that is attached (and free it up when it's detached) may have a global variable to manage ids, access to which needs to synchronised. We use constructors to implement this, so we select `CONFIG_CONSTRUCTORS` automatically when `RUST` is selected. Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
1 parent a2a2e10 commit 4b9a68f

File tree

8 files changed

+71
-7
lines changed

8 files changed

+71
-7
lines changed

init/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,7 @@ config RUST
20622062
depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV
20632063
depends on !MODVERSIONS
20642064
depends on !GCC_PLUGIN_RANDSTRUCT
2065+
select CONSTRUCTORS
20652066
default n
20662067
help
20672068
Enables Rust support in the kernel.

rust/kernel/str.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ where
338338
/// ```
339339
#[macro_export]
340340
macro_rules! c_str {
341-
($str:literal) => {{
341+
($str:expr) => {{
342342
const S: &str = concat!($str, "\0");
343343
const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
344344
C

rust/kernel/sync/condvar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl CondVar {
4848
/// # Safety
4949
///
5050
/// The caller must call `CondVar::init` before using the conditional variable.
51-
pub unsafe fn new() -> Self {
51+
pub const unsafe fn new() -> Self {
5252
Self {
5353
wait_list: Opaque::uninit(),
5454
_pin: PhantomPinned,

rust/kernel/sync/mod.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub use spinlock::SpinLock;
4747
#[doc(hidden)]
4848
#[macro_export]
4949
macro_rules! init_with_lockdep {
50-
($obj:expr, $name:literal) => {{
50+
($obj:expr, $name:expr) => {{
5151
static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
5252
core::mem::MaybeUninit::uninit();
5353
static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
@@ -85,6 +85,69 @@ pub trait NeedsLockClass {
8585
);
8686
}
8787

88+
/// Automatically initialises static instances of synchronisation primitives.
89+
///
90+
/// The syntax resembles that of regular static variables, except that the value assigned is that
91+
/// of the protected type (if one exists). In the examples below, all primitives except for
92+
/// [`CondVar`] require the inner value to be supplied.
93+
///
94+
/// # Examples
95+
///
96+
/// ```ignore
97+
/// # use kernel::{init_static_sync, sync::{CondVar, Mutex, RevocableMutex, SpinLock}};
98+
/// struct Test {
99+
/// a: u32,
100+
/// b: u32,
101+
/// }
102+
///
103+
/// init_static_sync! {
104+
/// static A: Mutex<Test> = Test { a: 10, b: 20 };
105+
///
106+
/// /// Documentation for `B`.
107+
/// pub static B: Mutex<u32> = 0;
108+
///
109+
/// pub(crate) static C: SpinLock<Test> = Test { a: 10, b: 20 };
110+
/// static D: CondVar;
111+
///
112+
/// static E: RevocableMutex<Test> = Test { a: 30, b: 40 };
113+
/// }
114+
/// ```
115+
#[macro_export]
116+
macro_rules! init_static_sync {
117+
($($(#[$outer:meta])* $v:vis static $id:ident : $t:ty $(= $value:expr)?;)*) => {
118+
$(
119+
$(#[$outer])*
120+
$v static $id: $t = {
121+
#[link_section = ".ctors"]
122+
#[used]
123+
static TMP: extern "C" fn() = {
124+
extern "C" fn constructor() {
125+
// SAFETY: This locally-defined function is only called from a constructor,
126+
// which guarantees that `$id` is not accessible from other threads
127+
// concurrently.
128+
#[allow(clippy::cast_ref_to_mut)]
129+
let mutable = unsafe { &mut *(&$id as *const _ as *mut $t) };
130+
// SAFETY: It's a shared static, so it cannot move.
131+
let pinned = unsafe { core::pin::Pin::new_unchecked(mutable) };
132+
$crate::init_with_lockdep!(pinned, stringify!($id));
133+
}
134+
constructor
135+
};
136+
$crate::init_static_sync!(@call_new $t, $($value)?)
137+
};
138+
)*
139+
};
140+
(@call_new $t:ty, $value:expr) => {{
141+
let v = $value;
142+
// SAFETY: the initialisation function is called by the constructor above.
143+
unsafe { <$t>::new(v) }
144+
}};
145+
(@call_new $t:ty,) => {
146+
// SAFETY: the initialisation function is called by the constructor above.
147+
unsafe { <$t>::new() }
148+
};
149+
}
150+
88151
/// Reschedules the caller's task if needed.
89152
pub fn cond_resched() -> bool {
90153
// SAFETY: No arguments, reschedules `current` if needed.

rust/kernel/sync/mutex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<T> Mutex<T> {
5353
/// # Safety
5454
///
5555
/// The caller must call [`Mutex::init_lock`] before using the mutex.
56-
pub unsafe fn new(t: T) -> Self {
56+
pub const unsafe fn new(t: T) -> Self {
5757
Self {
5858
mutex: Opaque::uninit(),
5959
data: UnsafeCell::new(t),

rust/kernel/sync/revocable_mutex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<T> RevocableMutex<T> {
8080
/// # Safety
8181
///
8282
/// The caller must call [`RevocableMutex::init`] before using the revocable mutex.
83-
pub unsafe fn new(data: T) -> Self {
83+
pub const unsafe fn new(data: T) -> Self {
8484
Self {
8585
// SAFETY: The safety requirements of this function require that `RevocableMutex::init`
8686
// be called before the returned object can be used. Mutex initialisation is called

rust/kernel/sync/spinlock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<T> SpinLock<T> {
9696
/// # Safety
9797
///
9898
/// The caller must call [`SpinLock::init_lock`] before using the spinlock.
99-
pub unsafe fn new(t: T) -> Self {
99+
pub const unsafe fn new(t: T) -> Self {
100100
Self {
101101
spin_lock: Opaque::uninit(),
102102
data: UnsafeCell::new(t),

rust/kernel/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ impl<T> Opaque<T> {
283283
}
284284

285285
/// Creates an uninitialised value.
286-
pub fn uninit() -> Self {
286+
pub const fn uninit() -> Self {
287287
Self(MaybeUninit::uninit())
288288
}
289289

0 commit comments

Comments
 (0)