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