summaryrefslogtreecommitdiff
path: root/rust/kernel/sync/lock/global.rs
blob: 480ee724e3cc4a6492b21ca6c8893f4672ca7cf9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// SPDX-License-Identifier: GPL-2.0

// Copyright (C) 2024 Google LLC.

//! Support for defining statics containing locks.

use crate::{
    str::CStr,
    sync::lock::{Backend, Guard, Lock},
    sync::{LockClassKey, LockedBy},
    types::Opaque,
};
use core::{
    cell::UnsafeCell,
    marker::{PhantomData, PhantomPinned},
};

/// Trait implemented for marker types for global locks.
///
/// See [`global_lock!`] for examples.
pub trait GlobalLockBackend {
    /// The name for this global lock.
    const NAME: &'static CStr;
    /// Item type stored in this global lock.
    type Item: 'static;
    /// The backend used for this global lock.
    type Backend: Backend + 'static;
    /// The class for this global lock.
    fn get_lock_class() -> &'static LockClassKey;
}

/// Type used for global locks.
///
/// See [`global_lock!`] for examples.
pub struct GlobalLock<B: GlobalLockBackend> {
    inner: Lock<B::Item, B::Backend>,
}

impl<B: GlobalLockBackend> GlobalLock<B> {
    /// Creates a global lock.
    ///
    /// # Safety
    ///
    /// * Before any other method on this lock is called, [`Self::init`] must be called.
    /// * The type `B` must not be used with any other lock.
    pub const unsafe fn new(data: B::Item) -> Self {
        Self {
            inner: Lock {
                state: Opaque::uninit(),
                data: UnsafeCell::new(data),
                _pin: PhantomPinned,
            },
        }
    }

    /// Initializes a global lock.
    ///
    /// # Safety
    ///
    /// Must not be called more than once on a given lock.
    pub unsafe fn init(&'static self) {
        // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name`
        // and `key` are valid indefinitely. The `state` is pinned since we have a `'static`
        // reference to `self`.
        //
        // We have exclusive access to the `state` since the caller of `new` promised to call
        // `init` before using any other methods. As `init` can only be called once, all other
        // uses of this lock must happen after this call.
        unsafe {
            B::Backend::init(
                self.inner.state.get(),
                B::NAME.as_char_ptr(),
                B::get_lock_class().as_ptr(),
            )
        }
    }

    /// Lock this global lock.
    pub fn lock(&'static self) -> GlobalGuard<B> {
        GlobalGuard {
            inner: self.inner.lock(),
        }
    }

    /// Try to lock this global lock.
    pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {
        Some(GlobalGuard {
            inner: self.inner.try_lock()?,
        })
    }
}

/// A guard for a [`GlobalLock`].
///
/// See [`global_lock!`] for examples.
pub struct GlobalGuard<B: GlobalLockBackend> {
    inner: Guard<'static, B::Item, B::Backend>,
}

impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> {
    type Target = B::Item;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

/// A version of [`LockedBy`] for a [`GlobalLock`].
///
/// See [`global_lock!`] for examples.
pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
    _backend: PhantomData<B>,
    value: UnsafeCell<T>,
}

// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
unsafe impl<T, B> Send for GlobalLockedBy<T, B>
where
    T: ?Sized,
    B: GlobalLockBackend,
    LockedBy<T, B::Item>: Send,
{
}

// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
where
    T: ?Sized,
    B: GlobalLockBackend,
    LockedBy<T, B::Item>: Sync,
{
}

impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> {
    /// Create a new [`GlobalLockedBy`].
    ///
    /// The provided value will be protected by the global lock indicated by `B`.
    pub fn new(val: T) -> Self {
        Self {
            value: UnsafeCell::new(val),
            _backend: PhantomData,
        }
    }
}

impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {
    /// Access the value immutably.
    ///
    /// The caller must prove shared access to the lock.
    pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {
        // SAFETY: The lock is globally unique, so there can only be one guard.
        unsafe { &*self.value.get() }
    }

    /// Access the value mutably.
    ///
    /// The caller must prove shared exclusive to the lock.
    pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {
        // SAFETY: The lock is globally unique, so there can only be one guard.
        unsafe { &mut *self.value.get() }
    }

    /// Access the value mutably directly.
    ///
    /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the
    /// lock.
    pub fn get_mut(&mut self) -> &mut T {
        self.value.get_mut()
    }
}

/// Defines a global lock.
///
/// The global mutex must be initialized before first use. Usually this is done by calling
/// [`GlobalLock::init`] in the module initializer.
///
/// # Examples
///
/// A global counter:
///
/// ```
/// # mod ex {
/// # use kernel::prelude::*;
/// kernel::sync::global_lock! {
///     // SAFETY: Initialized in module initializer before first use.
///     unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;
/// }
///
/// fn increment_counter() -> u32 {
///     let mut guard = MY_COUNTER.lock();
///     *guard += 1;
///     *guard
/// }
///
/// impl kernel::Module for MyModule {
///     fn init(_module: &'static ThisModule) -> Result<Self> {
///         // SAFETY: Called exactly once.
///         unsafe { MY_COUNTER.init() };
///
///         Ok(MyModule {})
///     }
/// }
/// # struct MyModule {}
/// # }
/// ```
///
/// A global mutex used to protect all instances of a given struct:
///
/// ```
/// # mod ex {
/// # use kernel::prelude::*;
/// use kernel::sync::{GlobalGuard, GlobalLockedBy};
///
/// kernel::sync::global_lock! {
///     // SAFETY: Initialized in module initializer before first use.
///     unsafe(uninit) static MY_MUTEX: Mutex<()> = ();
/// }
///
/// /// All instances of this struct are protected by `MY_MUTEX`.
/// struct MyStruct {
///     my_counter: GlobalLockedBy<u32, MY_MUTEX>,
/// }
///
/// impl MyStruct {
///     /// Increment the counter in this instance.
///     ///
///     /// The caller must hold the `MY_MUTEX` mutex.
///     fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {
///         let my_counter = self.my_counter.as_mut(guard);
///         *my_counter += 1;
///         *my_counter
///     }
/// }
///
/// impl kernel::Module for MyModule {
///     fn init(_module: &'static ThisModule) -> Result<Self> {
///         // SAFETY: Called exactly once.
///         unsafe { MY_MUTEX.init() };
///
///         Ok(MyModule {})
///     }
/// }
/// # struct MyModule {}
/// # }
/// ```
#[macro_export]
macro_rules! global_lock {
    {
        $(#[$meta:meta])* $pub:vis
        unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;
    } => {
        #[doc = ::core::concat!(
            "Backend type used by [`",
            ::core::stringify!($name),
            "`](static@",
            ::core::stringify!($name),
            ")."
        )]
        #[allow(non_camel_case_types, unreachable_pub)]
        $pub enum $name {}

        impl $crate::sync::lock::GlobalLockBackend for $name {
            const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name));
            type Item = $valuety;
            type Backend = $crate::global_lock_inner!(backend $kind);

            fn get_lock_class() -> &'static $crate::sync::LockClassKey {
                $crate::static_lock_class!()
            }
        }

        $(#[$meta])*
        $pub static $name: $crate::sync::lock::GlobalLock<$name> = {
            // Defined here to be outside the unsafe scope.
            let init: $valuety = $value;

            // SAFETY:
            // * The user of this macro promises to initialize the macro before use.
            // * We are only generating one static with this backend type.
            unsafe { $crate::sync::lock::GlobalLock::new(init) }
        };
    };
}
pub use global_lock;

#[doc(hidden)]
#[macro_export]
macro_rules! global_lock_inner {
    (backend Mutex) => {
        $crate::sync::lock::mutex::MutexBackend
    };
    (backend SpinLock) => {
        $crate::sync::lock::spinlock::SpinLockBackend
    };
}