1use core::marker::PhantomData;
6use core::pin::Pin;
7use core::ptr::addr_of_mut;
8use pin_init::{PinInit, pin_data, pin_init, pinned_drop};
9
10use crate::{
11 ExclusiveLockPolicy, LockPolicy, LockdepTracked, RawBrwLockPi, RawBrwLockPiReadPolicy,
12 RawBrwLockPiStorage, RawLock,
13};
14use lockdep::LockClass;
15
16type LockdepTrackedBrwLockReadPolicy = LockdepTracked<RawBrwLockPiStorage, RawBrwLockPiReadPolicy>;
17type LockdepTrackedBrwLockWritePolicy = <RawBrwLockPi as RawLock>::DefaultPolicy;
18
19#[repr(transparent)]
21#[pin_data]
22pub struct BrwLockPi<Class: LockClass> {
23 #[pin]
24 lock: RawBrwLockPi,
25 _marker: PhantomData<Class>,
26}
27
28unsafe impl<Class: LockClass> Sync for BrwLockPi<Class> {}
30unsafe impl<Class: LockClass> Send for BrwLockPi<Class> {}
32
33impl<Class: LockClass> BrwLockPi<Class> {
34 pub fn init() -> impl PinInit<Self, core::convert::Infallible> {
36 pin_init!(Self {
37 lock <- unsafe { <RawBrwLockPi as RawLock>::init(Class::ID) },
39 _marker: PhantomData,
40 })
41 }
42
43 #[inline]
45 pub fn read_lock(
46 &self,
47 ) -> impl PinInit<BrwLockPiReadGuard<'_, Class>, core::convert::Infallible> {
48 BrwLockPiReadGuard::new(self)
49 }
50
51 #[inline]
53 pub fn write_lock(
54 &self,
55 ) -> impl PinInit<BrwLockPiWriteGuard<'_, Class>, core::convert::Infallible> {
56 BrwLockPiWriteGuard::new(self)
57 }
58
59 #[inline]
61 pub fn raw_lock(&self) -> &RawBrwLockPi {
62 &self.lock
63 }
64}
65
66#[repr(C)]
68#[pin_data(PinnedDrop)]
69pub struct BrwLockPiReadGuard<'a, Class: LockClass> {
70 lock: &'a BrwLockPi<Class>,
71 #[pin]
72 state: <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::GuardState,
73 token: crate::LockToken<'a, Class>,
74}
75
76impl<'a, Class: LockClass> BrwLockPiReadGuard<'a, Class> {
77 pub fn new(lock: &'a BrwLockPi<Class>) -> impl PinInit<Self, core::convert::Infallible> {
79 unsafe {
82 pin_init::pin_init_from_closure(
83 move |this: *mut Self| -> Result<(), core::convert::Infallible> {
84 let lock_addr = addr_of_mut!((*this).lock);
85 core::ptr::write(lock_addr, lock);
86
87 let state_addr = addr_of_mut!((*this).state);
88 core::ptr::write(state_addr, Default::default());
89
90 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::acquire(
91 &lock.lock,
92 &mut *state_addr,
93 (),
94 );
95
96 let token_addr = addr_of_mut!((*this).token);
97 core::ptr::write(token_addr, crate::LockToken::new());
98
99 Ok(())
100 },
101 )
102 }
103 }
104
105 #[inline]
107 pub fn token(&self) -> &crate::LockToken<'a, Class> {
108 &self.token
109 }
110
111 #[inline]
113 pub fn is_locked_by(&self, target: &BrwLockPi<Class>) -> bool {
114 core::ptr::eq(self.lock, target)
115 }
116
117 #[inline]
120 pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
121 unsafe {
123 let me = self.get_unchecked_mut();
124 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::release(
125 &me.lock.lock,
126 &mut me.state,
127 );
128 let result = f();
129 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::reacquire(
130 &me.lock.lock,
131 &mut me.state,
132 );
133 result
134 }
135 }
136}
137
138#[pinned_drop]
139impl<'a, Class: LockClass> PinnedDrop for BrwLockPiReadGuard<'a, Class> {
140 fn drop(self: Pin<&mut Self>) {
141 unsafe {
145 let me = self.get_unchecked_mut();
146 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::release(
147 &me.lock.lock,
148 &mut me.state,
149 );
150 }
151 }
152}
153
154#[repr(C)]
156pub struct BrwLockPiWriteGuard<
157 'a,
158 Class: LockClass,
159 P: ExclusiveLockPolicy<RawBrwLockPi> = LockdepTrackedBrwLockWritePolicy,
160> {
161 lock: &'a BrwLockPi<Class>,
162 state: P::GuardState,
163 token: crate::LockToken<'a, Class>,
164}
165
166impl<'a, Class: LockClass, P: ExclusiveLockPolicy<RawBrwLockPi>> BrwLockPiWriteGuard<'a, Class, P> {
167 pub fn new(lock: &'a BrwLockPi<Class>) -> impl PinInit<Self, core::convert::Infallible>
169 where
170 P: ExclusiveLockPolicy<RawBrwLockPi, AcquireArgs = ()>,
171 {
172 unsafe {
175 pin_init::pin_init_from_closure(
176 move |this: *mut Self| -> Result<(), core::convert::Infallible> {
177 let lock_addr = addr_of_mut!((*this).lock);
178 core::ptr::write(lock_addr, lock);
179
180 let state_addr = addr_of_mut!((*this).state);
181 core::ptr::write(state_addr, Default::default());
182
183 P::acquire(&lock.lock, &mut *state_addr, ());
184
185 let token_addr = addr_of_mut!((*this).token);
186 core::ptr::write(token_addr, crate::LockToken::new());
187
188 Ok(())
189 },
190 )
191 }
192 }
193
194 #[inline]
196 pub fn token(&self) -> &crate::LockToken<'a, Class> {
197 &self.token
198 }
199
200 #[inline]
202 pub fn token_mut(self: Pin<&mut Self>) -> &mut crate::LockToken<'a, Class> {
203 let me = unsafe { self.get_unchecked_mut() };
206 &mut me.token
207 }
208
209 #[inline]
211 pub fn is_locked_by(&self, target: &BrwLockPi<Class>) -> bool {
212 core::ptr::eq(self.lock, target)
213 }
214
215 #[inline]
218 pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
219 unsafe {
221 let me = self.get_unchecked_mut();
222 P::release(&me.lock.lock, &mut me.state);
223 let result = f();
224 P::reacquire(&me.lock.lock, &mut me.state);
225 result
226 }
227 }
228}
229
230impl<'a, Class: LockClass, P: ExclusiveLockPolicy<RawBrwLockPi>> Drop
231 for BrwLockPiWriteGuard<'a, Class, P>
232{
233 #[inline]
234 fn drop(&mut self) {
235 unsafe {
239 P::release(&self.lock.lock, &mut self.state);
240 }
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 extern crate std;
247
248 use super::{LockdepTrackedBrwLockReadPolicy, LockdepTrackedBrwLockWritePolicy};
249 use crate::{BrwLockPi, LockPolicy, RawBrwLockPi, RawLock, guarded};
250 use pin_init::{pin_init, stack_pin_init};
251 use std::string::String;
252 use std::vec::Vec;
253
254 #[guarded]
255 struct Database {
256 #[brwlock]
257 lock: BrwLockPi,
258
259 #[guarded_by(lock)]
260 data: Vec<String>,
261
262 #[guarded_by(lock)]
263 query_count: u64,
264 }
265
266 fn read_data(db: &Database) -> usize {
267 lock!(let guard = db.read_lock());
268 let len = guard.data().len();
269
270 let fields = guard.fields();
271 let _ = fields.data.len();
272 let _ = *fields.query_count;
273
274 len
275 }
276
277 fn append_data(db: &Database, value: String) {
278 lock!(let mut guard = db.write_lock());
279 let fields = guard.as_mut().fields_mut();
280 fields.data.push(value);
281 *fields.query_count += 1;
282 }
283
284 #[test]
285 fn test_brwlock_projections() {
286 stack_pin_init!(let db = pin_init!(Database {
287 lock <- BrwLockPi::init(),
288 data: Vec::new().into(),
289 query_count: 0.into(),
290 }));
291
292 assert_eq!(read_data(&db), 0);
293 append_data(&db, String::from("hello"));
294 assert_eq!(read_data(&db), 1);
295
296 lock!(let guard = db.read_lock());
297 assert_eq!(guard.data()[0], "hello");
298 assert_eq!(*guard.query_count(), 1);
299 }
300
301 #[pin_init::pin_data]
302 struct BrwLockTest {
303 #[pin]
304 lock: RawBrwLockPi,
305 state: std::sync::atomic::AtomicU32,
306 kill: std::sync::atomic::AtomicBool,
307 }
308
309 fn run_test(readers: usize, writers: usize) {
310 use std::sync::atomic::Ordering;
311
312 stack_pin_init!(let test = pin_init!(BrwLockTest {
313 lock <- unsafe { <RawBrwLockPi as RawLock>::init(core::ptr::null()) },
315 state: std::sync::atomic::AtomicU32::new(0),
316 kill: std::sync::atomic::AtomicBool::new(false),
317 }));
318
319 std::thread::scope(|s| {
320 let mut threads = std::vec::Vec::new();
321
322 for _ in 0..readers {
323 threads.push(s.spawn(|| {
324 let mut state =
325 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::GuardState::default();
326 while !test.kill.load(Ordering::Relaxed) {
327 unsafe {
329 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::acquire(
330 &test.lock,
331 &mut state,
332 (),
333 );
334 }
335 let _ = test.state.fetch_add(1, Ordering::Relaxed);
336 std::thread::yield_now();
337 let _ = test.state.fetch_sub(1, Ordering::Relaxed);
338 unsafe {
340 <LockdepTrackedBrwLockReadPolicy as LockPolicy<RawBrwLockPi>>::release(
341 &test.lock,
342 &mut state,
343 );
344 }
345 std::thread::yield_now();
346 }
347 }));
348 }
349
350 for _ in 0..writers {
351 threads.push(s.spawn(|| {
352 let mut state = <LockdepTrackedBrwLockWritePolicy as LockPolicy<
353 RawBrwLockPi,
354 >>::GuardState::default();
355 while !test.kill.load(Ordering::Relaxed) {
356 unsafe {
358 <LockdepTrackedBrwLockWritePolicy as LockPolicy<RawBrwLockPi>>::acquire(
359 &test.lock,
360 &mut state,
361 (),
362 );
363 }
364 let _ = test.state.fetch_add(0x10000, Ordering::Relaxed);
365 std::thread::yield_now();
366 let _ = test.state.fetch_sub(0x10000, Ordering::Relaxed);
367 unsafe {
369 <LockdepTrackedBrwLockWritePolicy as LockPolicy<RawBrwLockPi>>::release(
370 &test.lock, &mut state,
371 );
372 }
373 std::thread::yield_now();
374 }
375 }));
376 }
377
378 let start = std::time::Instant::now();
379 while start.elapsed() < std::time::Duration::from_millis(300) {
380 let local_state = test.state.load(Ordering::Relaxed);
381 let num_readers = (local_state & 0xffff) as usize;
382 let num_writers = (local_state >> 16) as usize;
383
384 assert!(num_readers <= readers, "Too many readers: {}", num_readers);
385 assert!(num_writers <= 1, "Too many writers: {}", num_writers);
386 assert!(
387 num_readers == 0 || num_writers == 0,
388 "Both readers ({}) and writers ({}) active!",
389 num_readers,
390 num_writers
391 );
392
393 std::thread::yield_now();
394 }
395
396 test.kill.store(true, Ordering::SeqCst);
397 });
398 }
399
400 #[test]
401 fn test_parallel_readers() {
402 run_test(8, 0);
403 }
404
405 #[test]
406 fn test_single_writer() {
407 run_test(0, 4);
408 }
409
410 #[test]
411 fn test_readers_and_writers() {
412 run_test(4, 2);
413 }
414
415 #[allow(dead_code)]
416 struct CustomBrwLockClass;
417 impl lockdep::LockClass for CustomBrwLockClass {
418 const ID: *mut core::ffi::c_void = core::ptr::null_mut();
419 }
420
421 #[guarded]
422 struct CustomBrwLockStruct {
423 #[brwlock(CustomBrwLockClass)]
424 lock: BrwLockPi<CustomBrwLockClass>,
425 #[guarded_by(lock)]
426 value: u32,
427 }
428
429 #[test]
430 fn test_custom_brwlock_class() {
431 stack_pin_init!(let s = pin_init!(CustomBrwLockStruct {
432 lock <- BrwLockPi::init(),
433 value: 42.into(),
434 }));
435
436 lock!(let guard = s.read_lock());
437 assert_eq!(*guard.value(), 42);
438 }
439
440 #[guarded]
441 struct MultiLockBrwStruct {
442 #[brwlock]
443 rw: BrwLockPi,
444 #[mutex]
445 mu: crate::KMutex,
446 #[guarded_by(rw)]
447 only_rw: u32,
448 #[guarded_by(rw, mu)]
449 shared: u32,
450 #[pin]
451 #[guarded_by(rw, mu)]
452 pinned_shared: u32,
453 #[guarded_by(rw, mu)]
454 once_shared: crate::KOnceCell<u32>,
455 }
456
457 #[test]
458 fn test_multi_lock_brwlock_and_mutex() {
459 stack_pin_init!(let s = pin_init!(MultiLockBrwStruct {
460 rw <- BrwLockPi::init(),
461 mu <- crate::KMutex::init(),
462 only_rw: 1.into(),
463 shared: 10.into(),
464 pinned_shared: 100.into(),
465 once_shared: crate::KOnceCell::new(),
466 }));
467
468 {
469 lock!(let rg = s.read_rw());
470 assert_eq!(*rg.only_rw(), 1);
471 assert_eq!(*rg.shared(), 10);
472 assert_eq!(*rg.pinned_shared(), 100);
473 assert_eq!(rg.once_shared(), None);
474 assert_eq!(*rg.fields().shared, 10);
475 assert_eq!(*rg.as_token_guard().shared(), 10);
476 }
477 {
478 lock!(let mg = s.lock_mu());
479 assert_eq!(*mg.shared(), 10);
480 assert_eq!(*mg.pinned_shared(), 100);
481 assert_eq!(mg.once_shared(), None);
482 }
483 {
484 lock!(let mut wg = s.write_rw());
485 lock!(let mut mg = s.lock_mu());
486 *wg.as_mut().shared_mut(&mut mg) = 25;
487 assert_eq!(*wg.shared(), 25);
488 *mg.as_mut().shared_mut(&mut wg) = 50;
489 assert_eq!(*mg.shared(), 50);
490
491 *wg.as_mut().pinned_shared_mut(&mut mg) = 200;
492 assert_eq!(*mg.pinned_shared(), 200);
493
494 let _ = wg.as_mut().once_shared_cell(&mut mg).get_or_init(|| 300);
495 assert_eq!(wg.once_shared(), Some(&300));
496
497 let wf_mut = wg.as_mut().fields_mut();
498 *wf_mut.only_rw = 2;
499 assert_eq!(*wf_mut.shared, 50);
500 assert_eq!(*wf_mut.pinned_shared, 200);
501 assert_eq!(wf_mut.once_shared, Some(&300));
502
503 let mut wtg = wg.as_mut().as_token_guard_mut();
505 let mut mtg = mg.as_mut().as_token_guard_mut();
506 *wtg.reborrow().shared_mut(&mut mtg) = 75;
507 assert_eq!(*wtg.as_token_guard().shared(), 75);
508 *mtg.reborrow().shared_mut(&mut wtg) = 90;
509 assert_eq!(*wtg.shared(), 90);
510 }
511 }
512}