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
103#[pinned_drop]
104impl<'a, Class: LockClass> PinnedDrop for BrwLockPiReadGuard<'a, Class> {
105 fn drop(self: Pin<&mut Self>) {
106 unsafe {
110 let me = self.get_unchecked_mut();
111 let entry_addr = &mut me.lock_entry as *mut _;
112 me.lock.lock.release_read(entry_addr as *mut core::ffi::c_void);
113 }
114 }
115}
116
117#[repr(C)]
119#[pin_data(PinnedDrop)]
120pub struct BrwLockPiWriteGuard<'a, Class: LockClass> {
121 lock: &'a BrwLockPi<Class>,
122 #[pin]
123 lock_entry: LockEntryStorage,
124 token: crate::LockToken<'a, Class>,
125}
126
127impl<'a, Class: LockClass> BrwLockPiWriteGuard<'a, Class> {
128 pub fn new(lock: &'a BrwLockPi<Class>) -> impl PinInit<Self, core::convert::Infallible> {
130 unsafe {
133 pin_init::pin_init_from_closure(
134 move |this: *mut Self| -> Result<(), core::convert::Infallible> {
135 let lock_addr = core::ptr::addr_of_mut!((*this).lock);
136 core::ptr::write(lock_addr, lock);
137
138 let entry_addr = core::ptr::addr_of_mut!((*this).lock_entry);
139 core::ptr::write(entry_addr, LockEntryStorage::default());
140
141 lock.lock.acquire_write(entry_addr as *mut core::ffi::c_void);
142
143 let token_addr = core::ptr::addr_of_mut!((*this).token);
144 core::ptr::write(token_addr, crate::LockToken::new());
145
146 Ok(())
147 },
148 )
149 }
150 }
151
152 #[inline]
154 pub fn token(&self) -> &crate::LockToken<'a, Class> {
155 &self.token
156 }
157
158 #[inline]
160 pub fn token_mut(self: Pin<&mut Self>) -> &mut crate::LockToken<'a, Class> {
161 let me = unsafe { self.get_unchecked_mut() };
164 &mut me.token
165 }
166}
167
168#[pinned_drop]
169impl<'a, Class: LockClass> PinnedDrop for BrwLockPiWriteGuard<'a, Class> {
170 fn drop(self: Pin<&mut Self>) {
171 unsafe {
175 let me = self.get_unchecked_mut();
176 let entry_addr = &mut me.lock_entry as *mut _;
177 me.lock.lock.release_write(entry_addr as *mut core::ffi::c_void);
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 extern crate std;
185
186 use crate::{BrwLockPi, RawBrwLockPi, guarded};
187 use pin_init::{pin_init, stack_pin_init};
188 use std::string::String;
189 use std::vec::Vec;
190
191 #[guarded]
192 struct Database {
193 #[brwlock]
194 lock: BrwLockPi,
195
196 #[guarded_by(lock)]
197 data: Vec<String>,
198
199 #[guarded_by(lock)]
200 query_count: u64,
201 }
202
203 fn read_data(db: &Database) -> usize {
204 lock!(let guard = db.read_lock());
205 let len = guard.data().len();
206
207 let fields = guard.fields();
208 let _ = fields.data.len();
209 let _ = *fields.query_count;
210
211 len
212 }
213
214 fn append_data(db: &Database, value: String) {
215 lock!(let mut guard = db.write_lock());
216 let fields = guard.as_mut().fields_mut();
217 fields.data.push(value);
218 *fields.query_count += 1;
219 }
220
221 #[test]
222 fn test_brwlock_projections() {
223 stack_pin_init!(let db = pin_init!(Database {
224 lock <- BrwLockPi::init(),
225 data: Vec::new().into(),
226 query_count: 0.into(),
227 }));
228
229 assert_eq!(read_data(&db), 0);
230 append_data(&db, String::from("hello"));
231 assert_eq!(read_data(&db), 1);
232
233 lock!(let guard = db.read_lock());
234 assert_eq!(guard.data()[0], "hello");
235 assert_eq!(*guard.query_count(), 1);
236 }
237
238 #[pin_init::pin_data]
239 struct BrwLockTest {
240 #[pin]
241 lock: RawBrwLockPi,
242 state: std::sync::atomic::AtomicU32,
243 kill: std::sync::atomic::AtomicBool,
244 }
245
246 fn run_test(readers: usize, writers: usize) {
247 use std::sync::atomic::Ordering;
248
249 stack_pin_init!(let test = pin_init!(BrwLockTest {
250 lock <- unsafe { RawBrwLockPi::init(core::ptr::null()) },
251 state: std::sync::atomic::AtomicU32::new(0).into(),
252 kill: std::sync::atomic::AtomicBool::new(false).into(),
253 }));
254
255 std::thread::scope(|s| {
256 let mut threads = std::vec::Vec::new();
257
258 for _ in 0..readers {
259 threads.push(s.spawn(|| {
260 while !test.kill.load(Ordering::Relaxed) {
261 unsafe {
263 test.lock.acquire_read(core::ptr::null_mut());
264 }
265 test.state.fetch_add(1, Ordering::Relaxed);
266 std::thread::yield_now();
267 test.state.fetch_sub(1, Ordering::Relaxed);
268 unsafe {
270 test.lock.release_read(core::ptr::null_mut());
271 }
272 std::thread::yield_now();
273 }
274 }));
275 }
276
277 for _ in 0..writers {
278 threads.push(s.spawn(|| {
279 while !test.kill.load(Ordering::Relaxed) {
280 unsafe {
282 test.lock.acquire_write(core::ptr::null_mut());
283 }
284 test.state.fetch_add(0x10000, Ordering::Relaxed);
285 std::thread::yield_now();
286 test.state.fetch_sub(0x10000, Ordering::Relaxed);
287 unsafe {
289 test.lock.release_write(core::ptr::null_mut());
290 }
291 std::thread::yield_now();
292 }
293 }));
294 }
295
296 let start = std::time::Instant::now();
297 while start.elapsed() < std::time::Duration::from_millis(300) {
298 let local_state = test.state.load(Ordering::Relaxed);
299 let num_readers = (local_state & 0xffff) as usize;
300 let num_writers = (local_state >> 16) as usize;
301
302 assert!(num_readers <= readers, "Too many readers: {}", num_readers);
303 assert!(num_writers <= 1, "Too many writers: {}", num_writers);
304 assert!(
305 num_readers == 0 || num_writers == 0,
306 "Both readers ({}) and writers ({}) active!",
307 num_readers,
308 num_writers
309 );
310
311 std::thread::yield_now();
312 }
313
314 test.kill.store(true, Ordering::SeqCst);
315 });
316 }
317
318 #[test]
319 fn test_parallel_readers() {
320 run_test(8, 0);
321 }
322
323 #[test]
324 fn test_single_writer() {
325 run_test(0, 4);
326 }
327
328 #[test]
329 fn test_readers_and_writers() {
330 run_test(4, 2);
331 }
332}