1use core::marker::PhantomData;
6use core::pin::Pin;
7use pin_init::{PinInit, pin_data, pin_init, pinned_drop};
8
9use crate::{LockEntryStorage, RawBrwLockPi};
10use lockdep::LockClass;
11
12#[repr(transparent)]
14#[pin_data]
15pub struct BrwLockPi<Class: LockClass> {
16 #[pin]
17 lock: RawBrwLockPi,
18 _marker: PhantomData<Class>,
19}
20
21unsafe impl<Class: LockClass> Sync for BrwLockPi<Class> {}
23unsafe impl<Class: LockClass> Send for BrwLockPi<Class> {}
24
25impl<Class: LockClass> BrwLockPi<Class> {
26 pub fn init() -> impl PinInit<Self, core::convert::Infallible> {
28 pin_init!(Self {
29 lock <- unsafe { RawBrwLockPi::init(Class::ID) },
31 _marker: PhantomData,
32 })
33 }
34
35 #[inline]
37 pub fn read_lock(
38 &self,
39 ) -> impl PinInit<BrwLockPiReadGuard<'_, Class>, core::convert::Infallible> {
40 BrwLockPiReadGuard::new(self)
41 }
42
43 #[inline]
45 pub fn write_lock(
46 &self,
47 ) -> impl PinInit<BrwLockPiWriteGuard<'_, Class>, core::convert::Infallible> {
48 BrwLockPiWriteGuard::new(self)
49 }
50}
51
52#[repr(C)]
54#[pin_data(PinnedDrop)]
55pub struct BrwLockPiReadGuard<'a, Class: LockClass> {
56 lock: &'a BrwLockPi<Class>,
57 #[pin]
58 lock_entry: LockEntryStorage,
59 token: crate::LockToken<'a, Class>,
60}
61
62impl<'a, Class: LockClass> BrwLockPiReadGuard<'a, Class> {
63 pub fn new(lock: &'a BrwLockPi<Class>) -> impl PinInit<Self, core::convert::Infallible> {
65 unsafe {
68 pin_init::pin_init_from_closure(
69 move |this: *mut Self| -> Result<(), core::convert::Infallible> {
70 let lock_addr = core::ptr::addr_of_mut!((*this).lock);
71 core::ptr::write(lock_addr, lock);
72
73 let entry_addr = core::ptr::addr_of_mut!((*this).lock_entry);
74 core::ptr::write(entry_addr, LockEntryStorage::default());
75
76 lock.lock.acquire_read(entry_addr as *mut core::ffi::c_void);
77
78 let token_addr = core::ptr::addr_of_mut!((*this).token);
79 core::ptr::write(token_addr, crate::LockToken::new());
80
81 Ok(())
82 },
83 )
84 }
85 }
86
87 #[inline]
89 pub fn token(&self) -> &crate::LockToken<'a, Class> {
90 &self.token
91 }
92
93 #[inline]
95 pub fn token_mut(self: Pin<&mut Self>) -> &mut crate::LockToken<'a, Class> {
96 let me = unsafe { self.get_unchecked_mut() };
99 &mut me.token
100 }
101
102 #[inline]
105 pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
106 unsafe {
108 let me = self.get_unchecked_mut();
109 let entry_addr = &mut me.lock_entry as *mut _;
110 me.lock.lock.release_read(entry_addr as *mut core::ffi::c_void);
111 let result = f();
112 me.lock.lock.acquire_read(entry_addr as *mut core::ffi::c_void);
113 result
114 }
115 }
116}
117
118#[pinned_drop]
119impl<'a, Class: LockClass> PinnedDrop for BrwLockPiReadGuard<'a, Class> {
120 fn drop(self: Pin<&mut Self>) {
121 unsafe {
125 let me = self.get_unchecked_mut();
126 let entry_addr = &mut me.lock_entry as *mut _;
127 me.lock.lock.release_read(entry_addr as *mut core::ffi::c_void);
128 }
129 }
130}
131
132#[repr(C)]
134#[pin_data(PinnedDrop)]
135pub struct BrwLockPiWriteGuard<'a, Class: LockClass> {
136 lock: &'a BrwLockPi<Class>,
137 #[pin]
138 lock_entry: LockEntryStorage,
139 token: crate::LockToken<'a, Class>,
140}
141
142impl<'a, Class: LockClass> BrwLockPiWriteGuard<'a, Class> {
143 pub fn new(lock: &'a BrwLockPi<Class>) -> impl PinInit<Self, core::convert::Infallible> {
145 unsafe {
148 pin_init::pin_init_from_closure(
149 move |this: *mut Self| -> Result<(), core::convert::Infallible> {
150 let lock_addr = core::ptr::addr_of_mut!((*this).lock);
151 core::ptr::write(lock_addr, lock);
152
153 let entry_addr = core::ptr::addr_of_mut!((*this).lock_entry);
154 core::ptr::write(entry_addr, LockEntryStorage::default());
155
156 lock.lock.acquire_write(entry_addr as *mut core::ffi::c_void);
157
158 let token_addr = core::ptr::addr_of_mut!((*this).token);
159 core::ptr::write(token_addr, crate::LockToken::new());
160
161 Ok(())
162 },
163 )
164 }
165 }
166
167 #[inline]
169 pub fn token(&self) -> &crate::LockToken<'a, Class> {
170 &self.token
171 }
172
173 #[inline]
175 pub fn token_mut(self: Pin<&mut Self>) -> &mut crate::LockToken<'a, Class> {
176 let me = unsafe { self.get_unchecked_mut() };
179 &mut me.token
180 }
181
182 #[inline]
185 pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
186 unsafe {
188 let me = self.get_unchecked_mut();
189 let entry_addr = &mut me.lock_entry as *mut _;
190 me.lock.lock.release_write(entry_addr as *mut core::ffi::c_void);
191 let result = f();
192 me.lock.lock.acquire_write(entry_addr as *mut core::ffi::c_void);
193 result
194 }
195 }
196}
197
198#[pinned_drop]
199impl<'a, Class: LockClass> PinnedDrop for BrwLockPiWriteGuard<'a, Class> {
200 fn drop(self: Pin<&mut Self>) {
201 unsafe {
205 let me = self.get_unchecked_mut();
206 let entry_addr = &mut me.lock_entry as *mut _;
207 me.lock.lock.release_write(entry_addr as *mut core::ffi::c_void);
208 }
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 extern crate std;
215
216 use crate::{BrwLockPi, RawBrwLockPi, guarded};
217 use pin_init::{pin_init, stack_pin_init};
218 use std::string::String;
219 use std::vec::Vec;
220
221 #[guarded]
222 struct Database {
223 #[brwlock]
224 lock: BrwLockPi,
225
226 #[guarded_by(lock)]
227 data: Vec<String>,
228
229 #[guarded_by(lock)]
230 query_count: u64,
231 }
232
233 fn read_data(db: &Database) -> usize {
234 lock!(let guard = db.read_lock());
235 let len = guard.data().len();
236
237 let fields = guard.fields();
238 let _ = fields.data.len();
239 let _ = *fields.query_count;
240
241 len
242 }
243
244 fn append_data(db: &Database, value: String) {
245 lock!(let mut guard = db.write_lock());
246 let fields = guard.as_mut().fields_mut();
247 fields.data.push(value);
248 *fields.query_count += 1;
249 }
250
251 #[test]
252 fn test_brwlock_projections() {
253 stack_pin_init!(let db = pin_init!(Database {
254 lock <- BrwLockPi::init(),
255 data: Vec::new().into(),
256 query_count: 0.into(),
257 }));
258
259 assert_eq!(read_data(&db), 0);
260 append_data(&db, String::from("hello"));
261 assert_eq!(read_data(&db), 1);
262
263 lock!(let guard = db.read_lock());
264 assert_eq!(guard.data()[0], "hello");
265 assert_eq!(*guard.query_count(), 1);
266 }
267
268 #[pin_init::pin_data]
269 struct BrwLockTest {
270 #[pin]
271 lock: RawBrwLockPi,
272 state: std::sync::atomic::AtomicU32,
273 kill: std::sync::atomic::AtomicBool,
274 }
275
276 fn run_test(readers: usize, writers: usize) {
277 use std::sync::atomic::Ordering;
278
279 stack_pin_init!(let test = pin_init!(BrwLockTest {
280 lock <- unsafe { RawBrwLockPi::init(core::ptr::null()) },
281 state: std::sync::atomic::AtomicU32::new(0).into(),
282 kill: std::sync::atomic::AtomicBool::new(false).into(),
283 }));
284
285 std::thread::scope(|s| {
286 let mut threads = std::vec::Vec::new();
287
288 for _ in 0..readers {
289 threads.push(s.spawn(|| {
290 while !test.kill.load(Ordering::Relaxed) {
291 unsafe {
293 test.lock.acquire_read(core::ptr::null_mut());
294 }
295 test.state.fetch_add(1, Ordering::Relaxed);
296 std::thread::yield_now();
297 test.state.fetch_sub(1, Ordering::Relaxed);
298 unsafe {
300 test.lock.release_read(core::ptr::null_mut());
301 }
302 std::thread::yield_now();
303 }
304 }));
305 }
306
307 for _ in 0..writers {
308 threads.push(s.spawn(|| {
309 while !test.kill.load(Ordering::Relaxed) {
310 unsafe {
312 test.lock.acquire_write(core::ptr::null_mut());
313 }
314 test.state.fetch_add(0x10000, Ordering::Relaxed);
315 std::thread::yield_now();
316 test.state.fetch_sub(0x10000, Ordering::Relaxed);
317 unsafe {
319 test.lock.release_write(core::ptr::null_mut());
320 }
321 std::thread::yield_now();
322 }
323 }));
324 }
325
326 let start = std::time::Instant::now();
327 while start.elapsed() < std::time::Duration::from_millis(300) {
328 let local_state = test.state.load(Ordering::Relaxed);
329 let num_readers = (local_state & 0xffff) as usize;
330 let num_writers = (local_state >> 16) as usize;
331
332 assert!(num_readers <= readers, "Too many readers: {}", num_readers);
333 assert!(num_writers <= 1, "Too many writers: {}", num_writers);
334 assert!(
335 num_readers == 0 || num_writers == 0,
336 "Both readers ({}) and writers ({}) active!",
337 num_readers,
338 num_writers
339 );
340
341 std::thread::yield_now();
342 }
343
344 test.kill.store(true, Ordering::SeqCst);
345 });
346 }
347
348 #[test]
349 fn test_parallel_readers() {
350 run_test(8, 0);
351 }
352
353 #[test]
354 fn test_single_writer() {
355 run_test(0, 4);
356 }
357
358 #[test]
359 fn test_readers_and_writers() {
360 run_test(4, 2);
361 }
362
363 #[allow(dead_code)]
364 struct CustomBrwLockClass;
365 impl lockdep::LockClass for CustomBrwLockClass {
366 const ID: *mut core::ffi::c_void = core::ptr::null_mut();
367 }
368
369 #[guarded]
370 struct CustomBrwLockStruct {
371 #[brwlock(CustomBrwLockClass)]
372 lock: BrwLockPi<CustomBrwLockClass>,
373 #[guarded_by(lock)]
374 value: u32,
375 }
376
377 #[test]
378 fn test_custom_brwlock_class() {
379 stack_pin_init!(let s = pin_init!(CustomBrwLockStruct {
380 lock <- BrwLockPi::init(),
381 value: 42.into(),
382 }));
383
384 lock!(let guard = s.read_lock());
385 assert_eq!(*guard.value(), 42);
386 }
387}