1use crate::sync::{ResourceSignature, ResourceType};
2use shuttle_engine::future::batch_semaphore::{BatchSemaphore, Fairness};
3use shuttle_engine::runtime::execution::ExecutionState;
4use shuttle_engine::runtime::task::{TaskId, TaskSet};
5use std::cell::RefCell;
6use std::fmt::{Debug, Display};
7use std::ops::{Deref, DerefMut};
8use std::panic::{RefUnwindSafe, UnwindSafe};
9use std::sync::{LockResult, PoisonError, TryLockError, TryLockResult};
10use tracing::trace;
11
12const MAX_READS: usize = (u32::MAX >> 3) as usize;
15
16pub struct RwLock<T: ?Sized> {
22 state: RefCell<RwLockState>,
23 semaphore: BatchSemaphore,
24 inner: std::sync::RwLock<T>,
25}
26
27#[derive(Debug)]
28struct RwLockState {
29 holder: RwLockHolder,
30}
31
32#[derive(PartialEq, Eq, Debug)]
33enum RwLockHolder {
34 Read(TaskSet),
35 Write(TaskId),
36 None,
37}
38
39#[derive(PartialEq, Eq, Debug, Clone, Copy)]
40enum RwLockType {
41 Read,
42 Write,
43}
44
45impl RwLockType {
46 fn num_permits(&self) -> usize {
48 match self {
49 Self::Read => 1,
50 Self::Write => MAX_READS,
51 }
52 }
53}
54
55impl<T> RwLock<T> {
56 #[track_caller]
58 pub const fn new(value: T) -> Self {
59 let state = RwLockState {
60 holder: RwLockHolder::None,
61 };
62
63 Self {
64 inner: std::sync::RwLock::new(value),
65 semaphore: BatchSemaphore::const_new_with_signature(
66 MAX_READS,
67 Fairness::Unfair,
68 ResourceSignature::new_const(ResourceType::RwLock),
69 ),
70 state: RefCell::new(state),
71 }
72 }
73}
74
75impl<T: ?Sized> RwLock<T> {
76 pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
79 self.lock(RwLockType::Read);
80
81 match self.inner.try_read() {
82 Ok(guard) => Ok(RwLockReadGuard {
83 inner: Some(guard),
84 rwlock: self,
85 me: ExecutionState::me(),
86 }),
87 Err(TryLockError::Poisoned(err)) => Err(PoisonError::new(RwLockReadGuard {
88 inner: Some(err.into_inner()),
89 rwlock: self,
90 me: ExecutionState::me(),
91 })),
92 Err(TryLockError::WouldBlock) => panic!("rwlock state out of sync"),
93 }
94 }
95
96 pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
99 self.lock(RwLockType::Write);
100
101 match self.inner.try_write() {
102 Ok(guard) => Ok(RwLockWriteGuard {
103 inner: Some(guard),
104 rwlock: self,
105 me: ExecutionState::me(),
106 }),
107 Err(TryLockError::Poisoned(err)) => Err(PoisonError::new(RwLockWriteGuard {
108 inner: Some(err.into_inner()),
109 rwlock: self,
110 me: ExecutionState::me(),
111 })),
112 Err(TryLockError::WouldBlock) => panic!("rwlock state out of sync"),
113 }
114 }
115
116 pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
124 if self.try_lock(RwLockType::Read) {
125 match self.inner.try_read() {
126 Ok(guard) => Ok(RwLockReadGuard {
127 inner: Some(guard),
128 rwlock: self,
129 me: ExecutionState::me(),
130 }),
131 Err(TryLockError::Poisoned(err)) => Err(TryLockError::Poisoned(PoisonError::new(RwLockReadGuard {
132 inner: Some(err.into_inner()),
133 rwlock: self,
134 me: ExecutionState::me(),
135 }))),
136 Err(TryLockError::WouldBlock) => panic!("rwlock state out of sync"),
137 }
138 } else {
139 Err(TryLockError::WouldBlock)
140 }
141 }
142
143 pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
148 if self.try_lock(RwLockType::Write) {
149 match self.inner.try_write() {
150 Ok(guard) => Ok(RwLockWriteGuard {
151 inner: Some(guard),
152 rwlock: self,
153 me: ExecutionState::me(),
154 }),
155 Err(TryLockError::Poisoned(err)) => Err(TryLockError::Poisoned(PoisonError::new(RwLockWriteGuard {
156 inner: Some(err.into_inner()),
157 rwlock: self,
158 me: ExecutionState::me(),
159 }))),
160 Err(TryLockError::WouldBlock) => panic!("rwlock state out of sync"),
161 }
162 } else {
163 Err(TryLockError::WouldBlock)
164 }
165 }
166
167 #[inline]
172 pub fn get_mut(&mut self) -> LockResult<&mut T> {
173 self.inner.get_mut()
174 }
175
176 pub fn into_inner(self) -> LockResult<T>
178 where
179 T: Sized,
180 {
181 let state = self.state.borrow();
182 assert_eq!(state.holder, RwLockHolder::None);
183
184 self.semaphore.try_acquire(MAX_READS).unwrap();
186
187 self.inner.into_inner()
188 }
189
190 fn lock(&self, typ: RwLockType) {
192 let me = ExecutionState::me();
193
194 let mut state = self.state.borrow_mut();
195 trace!(
196 holder = ?state.holder,
197 semaphore = ?self.semaphore,
198 "acquiring {:?} lock on rwlock {:p}",
199 typ,
200 self,
201 );
202 drop(state);
203
204 state = self.state.borrow_mut();
206 assert!(
207 match &state.holder {
208 RwLockHolder::Write(writer) => *writer != me,
209 RwLockHolder::Read(readers) => !readers.contains(me),
210 RwLockHolder::None => true,
211 },
212 "deadlock! task {me:?} tried to acquire a RwLock it already holds"
213 );
214 drop(state);
215
216 let _ = self.semaphore.acquire_blocking(typ.num_permits());
221
222 state = self.state.borrow_mut();
223 match (typ, &mut state.holder) {
224 (RwLockType::Write, RwLockHolder::None) => {
225 state.holder = RwLockHolder::Write(me);
226 }
227 (RwLockType::Read, RwLockHolder::None) => {
228 let mut readers = TaskSet::new();
229 readers.insert(me);
230 state.holder = RwLockHolder::Read(readers);
231 }
232 (RwLockType::Read, RwLockHolder::Read(readers)) => {
233 assert!(readers.insert(me));
234 }
235 _ => {
236 panic!(
237 "resumed a waiting {:?} thread while the lock was in state {:?}",
238 typ, state.holder
239 );
240 }
241 }
242 trace!(
243 holder = ?state.holder,
244 semaphore = ?self.semaphore,
245 "acquired {:?} lock on rwlock {:p}",
246 typ,
247 self
248 );
249 drop(state);
250 }
251
252 fn try_lock(&self, typ: RwLockType) -> bool {
255 let me = ExecutionState::me();
256
257 let mut state = self.state.borrow_mut();
258 trace!(
259 holder = ?state.holder,
260 semaphore = ?self.semaphore,
261 "trying to acquire {:?} lock on rwlock {:p}",
262 typ,
263 self,
264 );
265 drop(state);
266
267 let mut acquired = self.semaphore.try_acquire(typ.num_permits()).is_ok();
269 if acquired {
270 state = self.state.borrow_mut();
271 match (typ, &mut state.holder) {
272 (RwLockType::Write, RwLockHolder::None) => {
273 state.holder = RwLockHolder::Write(me);
274 }
275 (RwLockType::Read, RwLockHolder::None) => {
276 let mut readers = TaskSet::new();
277 readers.insert(me);
278 state.holder = RwLockHolder::Read(readers);
279 }
280 (RwLockType::Read, RwLockHolder::Read(readers)) => {
281 acquired = readers.insert(me);
284 }
285 _ => (),
286 };
287 drop(state);
288 }
289
290 trace!(
291 "{} {:?} lock on rwlock {:p}",
292 if acquired { "acquired" } else { "failed to acquire" },
293 typ,
294 self,
295 );
296
297 acquired
298 }
299
300 #[inline]
302 pub fn clear_poison(&self) {
303 self.inner.clear_poison();
304 }
305}
306
307unsafe impl<T: Send + ?Sized> Send for RwLock<T> {}
312unsafe impl<T: Send + ?Sized> Sync for RwLock<T> {}
313
314impl<T: ?Sized> UnwindSafe for RwLock<T> {}
316impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
317
318impl<T: Default> Default for RwLock<T> {
319 fn default() -> Self {
320 Self::new(Default::default())
321 }
322}
323
324impl<T: ?Sized + Debug> Debug for RwLock<T> {
325 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326 Debug::fmt(&self.inner, f)
327 }
328}
329
330pub struct RwLockReadGuard<'a, T: ?Sized> {
332 inner: Option<std::sync::RwLockReadGuard<'a, T>>,
333 rwlock: &'a RwLock<T>,
334 me: TaskId,
335}
336
337impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
338 type Target = T;
339
340 fn deref(&self) -> &Self::Target {
341 self.inner.as_ref().unwrap().deref()
342 }
343}
344
345impl<T: Debug> Debug for RwLockReadGuard<'_, T> {
346 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
347 Debug::fmt(&self.inner.as_ref().unwrap(), f)
348 }
349}
350
351impl<T: Display + ?Sized> Display for RwLockReadGuard<'_, T> {
352 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
353 (**self).fmt(f)
354 }
355}
356
357impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
358 fn drop(&mut self) {
359 struct Unlock<'g, 'a, T: ?Sized>(&'g mut RwLockReadGuard<'a, T>);
364 impl<T: ?Sized> Drop for Unlock<'_, '_, T> {
365 #[inline]
366 fn drop(&mut self) {
367 let guard = &mut *self.0;
368 guard.inner = None;
369
370 let mut state = guard.rwlock.state.borrow_mut();
371 trace!(
372 holder = ?state.holder,
373 semaphore = ?guard.rwlock.semaphore,
374 "releasing Read lock on rwlock {:p}",
375 guard.rwlock
376 );
377 let RwLockHolder::Read(readers) = &mut state.holder else {
378 panic!("exiting a reader but rwlock is in the wrong state {:?}", state.holder);
379 };
380 assert!(readers.remove(guard.me));
381 if readers.is_empty() {
382 state.holder = RwLockHolder::None;
383 }
384 drop(state);
385 }
386 }
387 let unlock = Unlock(self);
388
389 unlock.0.rwlock.semaphore.release(RwLockType::Read.num_permits());
390 }
391}
392
393pub struct RwLockWriteGuard<'a, T: ?Sized> {
395 inner: Option<std::sync::RwLockWriteGuard<'a, T>>,
396 rwlock: &'a RwLock<T>,
397 me: TaskId,
398}
399
400impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
401 type Target = T;
402
403 fn deref(&self) -> &Self::Target {
404 self.inner.as_ref().unwrap().deref()
405 }
406}
407
408impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
409 fn deref_mut(&mut self) -> &mut Self::Target {
410 self.inner.as_mut().unwrap().deref_mut()
411 }
412}
413
414impl<T: Debug> Debug for RwLockWriteGuard<'_, T> {
415 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
416 Debug::fmt(&self.inner.as_ref().unwrap(), f)
417 }
418}
419
420impl<T: Display + ?Sized> Display for RwLockWriteGuard<'_, T> {
421 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
422 (**self).fmt(f)
423 }
424}
425
426impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
427 fn drop(&mut self) {
428 struct Unlock<'g, 'a, T: ?Sized>(&'g mut RwLockWriteGuard<'a, T>);
430 impl<T: ?Sized> Drop for Unlock<'_, '_, T> {
431 #[inline]
432 fn drop(&mut self) {
433 let guard = &mut *self.0;
434 let clear_poison = std::thread::panicking()
436 && !guard.rwlock.inner.is_poisoned()
437 && ExecutionState::unwinding_for_teardown();
438 guard.inner = None;
439 if clear_poison {
440 guard.rwlock.inner.clear_poison();
441 }
442
443 let mut state = guard.rwlock.state.borrow_mut();
444 trace!(
445 holder = ?state.holder,
446 semaphore = ?guard.rwlock.semaphore,
447 "releasing Write lock on rwlock {:p}",
448 guard.rwlock
449 );
450 assert_eq!(state.holder, RwLockHolder::Write(guard.me));
451 state.holder = RwLockHolder::None;
452 drop(state);
453 }
454 }
455 let unlock = Unlock(self);
456
457 unlock.0.rwlock.semaphore.release(RwLockType::Write.num_permits());
458 }
459}
460
461#[cfg(test)]
462mod tests {
463 use super::*;
464
465 #[test]
466 fn unique_resource_signature_rwlock() {
467 shuttle_schedulers::check_random(
468 || {
469 let rwlock1 = RwLock::new(0);
470 let rwlock2 = RwLock::new(0);
471 assert_ne!(rwlock1.semaphore.signature(), rwlock2.semaphore.signature());
472 },
473 1,
474 );
475 }
476}