1use core::marker::PhantomData;
6use core::pin::Pin;
7use pin_init::{PinInit, pin_data, pin_init, pin_init_from_closure, pinned_drop};
8
9use crate::{LockToken, RawLock, RawMutex};
10use lockdep::LockClass;
11
12#[repr(transparent)] #[pin_data]
18pub struct KMutex<Class: LockClass, M: RawLock = RawMutex> {
19 #[pin]
20 mutex: M,
21 _marker: PhantomData<Class>,
22}
23
24impl<Class: LockClass, M: RawLock> KMutex<Class, M> {
25 pub const fn new(mutex: M) -> Self {
27 Self { mutex, _marker: PhantomData }
28 }
29
30 pub fn init() -> impl PinInit<Self, core::convert::Infallible> {
32 pin_init!(Self {
33 mutex <- unsafe { M::init(Self::class_id()) },
34 _marker: PhantomData,
35 })
36 }
37
38 #[inline]
40 pub fn lock(&self) -> impl PinInit<KMutexGuard<'_, Class, M>, core::convert::Infallible> {
41 KMutexGuard::new(self)
42 }
43
44 const fn class_id() -> *const core::ffi::c_void {
45 if cfg!(feature = "lock_dep") { Class::ID } else { core::ptr::null() }
46 }
47}
48
49impl<Class: LockClass, M: RawLock> core::fmt::Debug for KMutex<Class, M> {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 f.debug_struct("KMutex").field("class", &core::any::type_name::<Class>()).finish()
52 }
53}
54
55#[repr(C)]
60#[pin_data(PinnedDrop)]
61pub struct KMutexGuard<'a, Class: LockClass, M: RawLock = RawMutex> {
62 mutex: &'a KMutex<Class, M>,
63
64 #[pin]
65 lock_entry: M::LockEntry,
66
67 state: M::GuardState,
68
69 token: LockToken<'a, Class>,
70}
71
72impl<'a, Class: LockClass, M: RawLock> KMutexGuard<'a, Class, M> {
73 pub fn new(mutex: &'a KMutex<Class, M>) -> impl PinInit<Self, core::convert::Infallible> {
75 unsafe {
78 pin_init_from_closure(move |this: *mut Self| -> Result<(), core::convert::Infallible> {
79 let mutex_addr = core::ptr::addr_of_mut!((*this).mutex);
83 core::ptr::write(mutex_addr, mutex);
84
85 let entry_addr = core::ptr::addr_of_mut!((*this).lock_entry);
86 core::ptr::write(entry_addr, M::LockEntry::default());
87
88 let state = mutex.mutex.acquire(entry_addr);
89
90 let state_addr = core::ptr::addr_of_mut!((*this).state);
91 core::ptr::write(state_addr, state);
92
93 let token_addr = core::ptr::addr_of_mut!((*this).token);
94 core::ptr::write(token_addr, LockToken::new());
95
96 Ok(())
97 })
98 }
99 }
100
101 #[inline]
103 pub fn token(&self) -> &LockToken<'a, Class> {
104 &self.token
105 }
106
107 #[inline]
109 pub fn token_mut(self: Pin<&mut Self>) -> &mut LockToken<'a, Class> {
110 let me = unsafe { self.get_unchecked_mut() };
113 &mut me.token
114 }
115}
116
117#[pinned_drop]
118impl<'a, Class: LockClass, M: RawLock> PinnedDrop for KMutexGuard<'a, Class, M> {
119 fn drop(self: Pin<&mut Self>) {
123 unsafe {
124 let me = self.get_unchecked_mut();
125 let entry_addr = &mut me.lock_entry as *mut _;
126 me.mutex.mutex.release(entry_addr, me.state);
127 }
128 }
129}
130
131#[cfg(not(feature = "kernel"))]
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use crate::{KCell, RawMutex, guarded};
136 use lockdep::LockClass;
137 use pin_init::{pin_init, stack_pin_init};
138
139 struct MyClass;
140 impl LockClass for MyClass {
141 const ID: *mut core::ffi::c_void = core::ptr::null_mut();
142 }
143
144 #[pin_init::pin_data]
145 struct MyStruct {
146 #[pin]
147 mu: KMutex<MyClass>,
148 data1: KCell<u32, MyClass>,
149 data2: KCell<i32, MyClass>,
150 }
151
152 #[test]
153 fn test_basic_token_access() {
154 stack_pin_init!(let s = pin_init!(MyStruct {
155 mu <- KMutex::init(),
156 data1: KCell::new(10),
157 data2: KCell::new(-5),
158 }));
159
160 lock!(let mut guard = s.mu.lock());
161
162 unsafe {
163 assert_eq!(*s.data1.get(guard.token()), 10);
164 assert_eq!(*s.data2.get(guard.token()), -5);
165 }
166 unsafe {
167 let token_mut = guard.as_mut().token_mut();
168 *s.data1.get_mut(token_mut) = 20;
169 assert_eq!(*s.data1.get(guard.token()), 20);
170 }
171 }
172
173 #[guarded]
174 struct MyGuardedStruct {
175 #[mutex]
176 mu: KMutex,
177 #[guarded_by(mu)]
178 data1: u32,
179 #[guarded_by(mu)]
180 data2: i32,
181 }
182
183 #[test]
184 fn test_macro_guarded() {
185 stack_pin_init!(let s = pin_init!(MyGuardedStruct {
186 mu <- KMutex::init(),
187 data1: 100.into(),
188 data2: (-50).into(),
189 }));
190
191 {
192 lock!(let mut guard = s.lock_mu());
193
194 assert_eq!(*guard.data1(), 100);
196 assert_eq!(*guard.data2(), -50);
197
198 *guard.as_mut().data1_mut() = 200;
199 assert_eq!(*guard.data1(), 200);
200
201 let fields = guard.as_mut().fields_mut();
203 *fields.data1 += 50;
204 *fields.data2 += 50;
205 }
206
207 lock!(let guard = s.lock_mu());
209 assert_eq!(*guard.data1(), 250);
210 assert_eq!(*guard.data2(), 0);
211 }
212
213 #[test]
214 fn test_kmutex_init() {
215 stack_pin_init!(let mu = KMutex::<MyClass>::init());
216 lock!(mu.lock());
217 }
218
219 #[test]
220 fn test_kmutex_debug() {
221 extern crate std;
222 stack_pin_init!(let mu = KMutex::<MyClass>::init());
223 let debug_str = std::format!("{:?}", mu);
224 assert!(debug_str.contains("KMutex"));
225 }
226
227 #[guarded]
228 struct MyMultiGuardedStruct {
229 #[mutex]
230 mu1: KMutex,
231 #[mutex]
232 mu2: KMutex,
233 #[guarded_by(mu1)]
234 data1: u32,
235 #[guarded_by(mu2)]
236 data2: i32,
237 }
238
239 #[test]
240 fn test_macro_multi_guarded() {
241 stack_pin_init!(let s = pin_init!(MyMultiGuardedStruct {
242 mu1 <- KMutex::init(),
243 mu2 <- KMutex::init(),
244 data1: 10.into(),
245 data2: 20.into(),
246 }));
247
248 lock!(let mut guard1 = s.lock_mu1());
249 lock!(let mut guard2 = s.lock_mu2());
250
251 assert_eq!(*guard1.data1(), 10);
252 assert_eq!(*guard2.data2(), 20);
253 *guard1.as_mut().data1_mut() = 15;
254 *guard2.as_mut().data2_mut() = 25;
255 assert_eq!(*guard1.data1(), 15);
256 assert_eq!(*guard2.data2(), 25);
257 }
258
259 #[guarded]
260 struct MyDefaultGuardedStruct {
261 #[mutex]
262 mu: KMutex,
263 #[guarded_by(mu)]
264 data: u32,
265 }
266
267 #[test]
268 fn test_derive_default_guarded() {
269 stack_pin_init!(let s = pin_init!(MyDefaultGuardedStruct {
270 mu <- KMutex::init(),
271 data: 0.into(),
272 }));
273 lock!(let guard = s.lock_mu());
274 assert_eq!(*guard.data(), 0);
275 }
276
277 #[guarded]
278 struct MyGenericLockGuardedStruct<L: RawLock> {
279 #[mutex]
280 mu: KMutex<L>,
281 #[guarded_by(mu)]
282 data: u32,
283 }
284
285 #[test]
286 fn test_macro_generic_lock_guarded() {
287 stack_pin_init!(let s = pin_init!(MyGenericLockGuardedStruct::<RawMutex> {
288 mu <- KMutex::init(),
289 data: 100.into(),
290 }));
291
292 lock!(let guard = s.lock_mu());
293 assert_eq!(*guard.data(), 100);
294 }
295
296 #[guarded]
297 struct MyGenericGuardedStruct<T> {
298 #[mutex]
299 mu: KMutex,
300 #[guarded_by(mu)]
301 data: T,
302 }
303
304 #[test]
305 fn test_macro_generic_guarded() {
306 stack_pin_init!(let s = pin_init!(MyGenericGuardedStruct::<u32> {
307 mu <- KMutex::init(),
308 data: 0.into(),
309 }));
310 lock!(let mut guard = s.lock_mu());
311 assert_eq!(*guard.data(), 0);
312
313 *guard.as_mut().data_mut() = 42;
314 assert_eq!(*guard.data(), 42);
315
316 let fields = guard.as_mut().fields_mut();
317 *fields.data = 100;
318
319 let fields_shared = guard.fields();
320 assert_eq!(*fields_shared.data, 100);
321 }
322
323 #[guarded]
324 struct MyExplicitParentGuardedStruct {
325 #[mutex]
326 mu: KMutex,
327 #[guarded_by(mu)]
328 data: u32,
329 pub label: &'static str,
330 }
331
332 impl MyExplicitParentGuardedStruct {
333 pub fn has_label(&self) -> bool {
334 !self.label.is_empty()
335 }
336 }
337
338 impl<'a> MyExplicitParentGuardedStructMuGuard<'a> {
339 pub fn process_with_context(self: Pin<&mut Self>) {
340 let me = unsafe { self.get_unchecked_mut() };
341 let has_label = me.parent.has_label();
342 let label = me.parent.label;
343 if has_label && label == "apply_update" {
344 unsafe {
345 let mut_self = Pin::new_unchecked(me);
346 let fields = mut_self.fields_mut();
347 *fields.data = 100;
348 }
349 }
350 }
351 }
352
353 #[test]
354 fn test_macro_guard_explicit_parent_access() {
355 stack_pin_init!(let s = pin_init!(MyExplicitParentGuardedStruct {
356 mu <- KMutex::init(),
357 data: 0.into(),
358 label: "apply_update",
359 }));
360
361 {
362 lock!(let mut guard = s.lock_mu());
363 guard.as_mut().process_with_context();
364 }
365
366 lock!(let guard = s.lock_mu());
367 assert_eq!(*guard.data(), 100);
368 }
369}