···7474 use std::sync::mpsc::{TryRecvError, channel};
75757676 use super::*;
7777- use crate::loom::{Arc, thread};
7777+ use crate::loom::sync::Arc;
7878+ use crate::loom::thread;
78797980 #[test]
8081 fn test_barrier() {
+3-2
libs/spin/src/lazy_lock.rs
···14141515use super::Once;
1616use super::once::ExclusiveState;
1717-use crate::loom::UnsafeCell;
1717+use crate::loom::cell::UnsafeCell;
18181919union Data<T, F> {
2020 value: ManuallyDrop<T>,
···170170 use std::cell::LazyCell;
171171172172 use super::*;
173173- use crate::loom::{AtomicUsize, Ordering, thread};
173173+ use crate::loom::sync::atomic::{AtomicUsize, Ordering};
174174+ use crate::loom::thread;
174175 use crate::{Mutex, OnceLock};
175176176177 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
+1-1
libs/spin/src/lib.rs
···2727pub use backoff::Backoff;
2828pub use barrier::{Barrier, BarrierWaitResult};
2929pub use lazy_lock::LazyLock;
3030-pub use mutex::{Mutex, MutexGuard};
3030+pub use mutex::{Mutex, MutexGuard, RawMutex};
3131pub use once::{ExclusiveState, Once};
3232pub use once_lock::OnceLock;
3333#[cfg(feature = "thread-local")]
···55// http://opensource.org/licenses/MIT>, at your option. This file may not be
66// copied, modified, or distributed except according to those terms.
7788-// Mutex
99-// A mutual exclusion primitive useful for protecting shared data
1010-// MutexGuard
1111-// An RAII implementation of a “scoped lock” of a mutex. When this structure is dropped (falls out of scope), the lock will be unlocked.
1212-// MappedMutexGuard
1313-// An RAII mutex guard returned by MutexGuard::map, which can point to a subfield of the protected data.
1414-// ArcMutexGuardarc_lock
1515-// An RAII mutex guard returned by the Arc locking operations on Mutex.
88+use core::sync::atomic::{AtomicBool, Ordering};
1691717-use core::marker::PhantomData;
1818-use core::ops::{Deref, DerefMut};
1919-use core::{fmt, mem};
1010+use crate::Backoff;
20112121-use util::loom_const_fn;
1212+pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
1313+pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;
22142323-use crate::backoff::Backoff;
2424-use crate::loom::{AtomicBool, Ordering, UnsafeCell};
2525-2626-/// A mutual exclusion primitive useful for protecting shared data
2727-///
2828-/// This mutex will block threads waiting for the lock to become available. The
2929-/// mutex can also be statically initialized or created via a `new`
3030-/// constructor. Each mutex has a type parameter which represents the data that
3131-/// it is protecting. The data can only be accessed through the RAII guards
3232-/// returned from `lock` and `try_lock`, which guarantees that the data is only
3333-/// ever accessed when the mutex is locked.
3434-pub struct Mutex<T: ?Sized> {
1515+pub struct RawMutex {
3516 lock: AtomicBool,
3636- data: UnsafeCell<T>,
3717}
38183939-/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
4040-/// dropped (falls out of scope), the lock will be unlocked.
4141-///
4242-/// The data protected by the mutex can be accessed through this guard via its
4343-/// `Deref` and `DerefMut` implementations.
4444-#[clippy::has_significant_drop]
4545-#[must_use = "if unused the Mutex will immediately unlock"]
4646-pub struct MutexGuard<'a, T: ?Sized> {
4747- mutex: &'a Mutex<T>,
4848- marker: PhantomData<&'a mut T>,
4949-}
1919+#[allow(clippy::undocumented_unsafe_blocks, reason = "TODO")]
2020+unsafe impl lock_api::RawMutex for RawMutex {
2121+ type GuardMarker = lock_api::GuardSend;
50225151-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
5252-unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
5353-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
5454-unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
5555-5656-impl<T> Mutex<T> {
5757- loom_const_fn! {
5858- pub const fn new(val: T) -> Mutex<T> {
5959- Mutex {
6060- lock: AtomicBool::new(false),
6161- data: UnsafeCell::new(val),
6262- }
6363- }
6464- }
6565-6666- /// Consumes this mutex, returning the underlying data.
6767- #[inline]
6868- pub fn into_inner(self) -> T {
6969- self.data.into_inner()
7070- }
7171-}
7272-7373-impl<T: ?Sized> Mutex<T> {
7474- /// Creates a new `MutexGuard` without checking if the mutex is locked.
7575- ///
7676- /// # Safety
7777- ///
7878- /// This method must only be called if the thread logically holds the lock.
7979- ///
8080- /// Calling this function when a guard has already been produced is undefined behaviour unless
8181- /// the guard was forgotten with `mem::forget`.
8282- #[inline]
8383- pub unsafe fn make_guard_unchecked(&self) -> MutexGuard<'_, T> {
8484- MutexGuard {
8585- mutex: self,
8686- marker: PhantomData,
8787- }
8888- }
2323+ const INIT: Self = Self {
2424+ lock: AtomicBool::new(false),
2525+ };
89269090- /// Acquires a mutex, blocking the current thread until it is able to do so.
9191- ///
9292- /// This function will block the local thread until it is available to acquire
9393- /// the mutex. Upon returning, the thread is the only thread with the mutex
9494- /// held. An RAII guard is returned to allow scoped unlock of the lock. When
9595- /// the guard goes out of scope, the mutex will be unlocked.
9696- ///
9797- /// Attempts to lock a mutex in the thread which already holds the lock will
9898- /// result in a deadlock.
9999- #[inline]
100100- pub fn lock(&self) -> MutexGuard<'_, T> {
2727+ fn lock(&self) {
10128 let mut boff = Backoff::default();
10229 while self
10330 .lock
···10835 boff.spin();
10936 }
11037 }
111111-112112- // Safety: The lock is held, as required.
113113- unsafe { self.make_guard_unchecked() }
11438 }
11539116116- /// Try to lock this mutex, returning a lock guard if successful.
117117- ///
118118- /// Like [`Self::lock`] the lock will be unlocked when the guard is dropped, but *unlike*
119119- /// [`Self::lock`] this method never blocks.
120120- #[inline]
121121- pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
122122- if self
123123- .lock
4040+ fn try_lock(&self) -> bool {
4141+ self.lock
12442 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
12543 .is_ok()
126126- {
127127- // SAFETY: The lock is held, as required.
128128- Some(unsafe { self.make_guard_unchecked() })
129129- } else {
130130- None
131131- }
13244 }
13345134134- /// Try to lock this mutex, returning a lock guard if successful.
135135- ///
136136- /// Like [`Self::lock`] the lock will be unlocked when the guard is dropped, but *unlike*
137137- /// [`Self::lock`] this method never blocks.
138138- ///
139139- /// Unlike [`Self::try_lock`] this method can spuriously fail even if the mutex is unlocked,
140140- /// this makes this method only suitable to be called in loops or similar scenarios, but might
141141- /// result in more efficient code on some platforms.
142142- #[inline]
143143- pub fn try_lock_weak(&self) -> Option<MutexGuard<'_, T>> {
144144- if self
145145- .lock
146146- .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
147147- .is_ok()
148148- {
149149- // SAFETY: The lock is held, as required.
150150- Some(unsafe { self.make_guard_unchecked() })
151151- } else {
152152- None
153153- }
154154- }
155155-156156- /// Returns a mutable reference to the underlying data.
157157- ///
158158- /// Since this call borrows the `Mutex` mutably, no actual locking needs to
159159- /// take place---the mutable borrow statically guarantees no locks exist.
160160- #[inline]
161161- pub fn get_mut(&mut self) -> &mut T {
162162- // Safety: We hold a mutable reference to the Mutex so getting a mutable reference to the
163163- // data is safe
164164- self.data.with_mut(|data| unsafe { &mut *data })
165165- }
166166-167167- /// Checks whether the mutex is currently locked.
168168- #[inline]
169169- pub fn is_locked(&self) -> bool {
170170- self.lock.load(Ordering::Relaxed)
171171- }
172172-173173- /// Forcibly unlocks the mutex.
174174- ///
175175- /// This is useful when combined with `mem::forget` to hold a lock without
176176- /// the need to maintain a `MutexGuard` object alive, for example when
177177- /// dealing with FFI.
178178- ///
179179- /// # Safety
180180- ///
181181- /// This method must only be called if the current thread logically owns a
182182- /// `MutexGuard` but that guard has been discarded using `mem::forget`.
183183- /// Behavior is undefined if a mutex is unlocked when not locked.
184184- #[inline]
185185- pub unsafe fn force_unlock(&self) {
186186- self.lock.store(false, Ordering::Release);
187187- }
188188-}
189189-190190-impl<T: Default> Default for Mutex<T> {
191191- #[inline]
192192- fn default() -> Mutex<T> {
193193- Mutex::new(Default::default())
194194- }
195195-}
196196-197197-impl<T> From<T> for Mutex<T> {
198198- #[inline]
199199- fn from(t: T) -> Mutex<T> {
200200- Mutex::new(t)
201201- }
202202-}
203203-204204-impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
205205- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206206- match self.try_lock() {
207207- Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
208208- None => {
209209- struct LockedPlaceholder;
210210- impl fmt::Debug for LockedPlaceholder {
211211- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212212- f.write_str("<locked>")
213213- }
214214- }
215215-216216- f.debug_struct("Mutex")
217217- .field("data", &LockedPlaceholder)
218218- .finish()
219219- }
220220- }
221221- }
222222-}
223223-224224-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
225225-unsafe impl<'a, T: ?Sized + Sync + 'a> Sync for MutexGuard<'a, T> {}
226226-227227-impl<'a, T: ?Sized + 'a> MutexGuard<'a, T> {
228228- /// Returns a reference to the original `Mutex` object.
229229- pub fn mutex(s: &Self) -> &'a Mutex<T> {
230230- s.mutex
231231- }
232232-233233- /// Leaks the mutex guard and returns a mutable reference to the data
234234- /// protected by the mutex.
235235- ///
236236- /// This will leave the `Mutex` in a locked state.
237237- #[inline]
238238- pub fn leak(s: Self) -> &'a mut T {
239239- // Safety: MutexGuard always holds the lock, so it is safe to access the data
240240- let r = s.mutex.data.with_mut(|r| unsafe { &mut *r });
241241- mem::forget(s);
242242- r
243243- }
244244-245245- pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
246246- where
247247- F: FnOnce() -> U,
248248- {
249249- struct DropGuard<'a, T: ?Sized> {
250250- mutex: &'a Mutex<T>,
251251- }
252252- impl<T: ?Sized> Drop for DropGuard<'_, T> {
253253- fn drop(&mut self) {
254254- mem::forget(self.mutex.lock());
255255- }
256256- }
257257-258258- // Safety: A MutexGuard always holds the lock.
259259- unsafe {
260260- s.mutex.force_unlock();
261261- }
262262- let _guard = DropGuard { mutex: s.mutex };
263263- f()
264264- }
265265-}
266266-267267-impl<'a, T: ?Sized + 'a> Deref for MutexGuard<'a, T> {
268268- type Target = T;
269269- #[inline]
270270- fn deref(&self) -> &T {
271271- // Safety: MutexGuard always holds the lock, so it is safe to access the data
272272- self.mutex.data.with(|data| unsafe { &*data })
273273- }
274274-}
275275-276276-impl<'a, T: ?Sized + 'a> DerefMut for MutexGuard<'a, T> {
277277- #[inline]
278278- fn deref_mut(&mut self) -> &mut T {
279279- // Safety: MutexGuard always holds the lock, so it is safe to access the data
280280- self.mutex.data.with_mut(|data| unsafe { &mut *data })
281281- }
282282-}
283283-284284-impl<'a, T: ?Sized + 'a> Drop for MutexGuard<'a, T> {
285285- #[inline]
286286- fn drop(&mut self) {
287287- // Safety: A MutexGuard always holds the lock.
288288- unsafe {
289289- self.mutex.force_unlock();
290290- }
291291- }
292292-}
293293-294294-impl<'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for MutexGuard<'a, T> {
295295- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296296- fmt::Debug::fmt(&**self, f)
297297- }
298298-}
299299-300300-impl<'a, T: fmt::Display + ?Sized + 'a> fmt::Display for MutexGuard<'a, T> {
301301- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302302- (**self).fmt(f)
303303- }
304304-}
305305-306306-#[cfg(feature = "lock_api")]
307307-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
308308-unsafe impl lock_api::RawMutex for Mutex<()> {
309309- #[allow(clippy::declare_interior_mutable_const, reason = "TODO")]
310310- const INIT: Self = Mutex::new(());
311311- type GuardMarker = lock_api::GuardSend;
312312-313313- fn lock(&self) {
314314- let g = Mutex::lock(self);
315315- mem::forget(g);
316316- }
317317-318318- fn try_lock(&self) -> bool {
319319- let g = Mutex::try_lock(self);
320320- let ret = g.is_some();
321321- mem::forget(g);
322322- ret
323323- }
4646+ // fn try_lock_weak(&self) -> bool {
4747+ // self.lock
4848+ // .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
4949+ // .is_ok()
5050+ // }
3245132552 unsafe fn unlock(&self) {
326326- // Safety: ensured by caller
327327- unsafe {
328328- Mutex::force_unlock(self);
329329- }
5353+ self.lock.store(false, Ordering::Release);
33054 }
3315533256 fn is_locked(&self) -> bool {
333333- Mutex::is_locked(self)
5757+ self.lock.load(Ordering::Relaxed)
33458 }
33559}
33660337337-#[cfg(test)]
338338-mod tests {
339339- use core::fmt::Debug;
340340- use std::{hint, mem};
341341-342342- use super::*;
343343- use crate::loom::{Arc, AtomicUsize};
344344-345345- #[derive(Eq, PartialEq, Debug)]
346346- struct NonCopy(i32);
347347-348348- #[derive(Eq, PartialEq, Debug)]
349349- struct NonCopyNeedsDrop(i32);
350350-351351- impl Drop for NonCopyNeedsDrop {
352352- fn drop(&mut self) {
353353- hint::black_box(());
354354- }
355355- }
356356-357357- #[test]
358358- fn test_needs_drop() {
359359- assert!(!mem::needs_drop::<NonCopy>());
360360- assert!(mem::needs_drop::<NonCopyNeedsDrop>());
361361- }
362362-363363- #[test]
364364- fn smoke() {
365365- let m = Mutex::new(());
366366- drop(m.lock());
367367- drop(m.lock());
368368- }
369369-370370- #[test]
371371- fn try_lock() {
372372- let mutex = Mutex::<_>::new(42);
373373-374374- // First lock succeeds
375375- let a = mutex.try_lock();
376376- assert_eq!(a.as_ref().map(|r| **r), Some(42));
377377-378378- // Additional lock fails
379379- let b = mutex.try_lock();
380380- assert!(b.is_none());
381381-382382- // After dropping lock, it succeeds again
383383- drop(a);
384384- let c = mutex.try_lock();
385385- assert_eq!(c.as_ref().map(|r| **r), Some(42));
386386- }
387387-388388- #[test]
389389- fn test_into_inner() {
390390- let m = Mutex::<_>::new(NonCopy(10));
391391- assert_eq!(m.into_inner(), NonCopy(10));
392392- }
393393-394394- #[test]
395395- fn test_into_inner_drop() {
396396- struct Foo(Arc<AtomicUsize>);
397397- impl Drop for Foo {
398398- fn drop(&mut self) {
399399- self.0.fetch_add(1, Ordering::SeqCst);
400400- }
401401- }
402402- let num_drops = Arc::new(AtomicUsize::new(0));
403403- let m = Mutex::<_>::new(Foo(num_drops.clone()));
404404- assert_eq!(num_drops.load(Ordering::SeqCst), 0);
405405- {
406406- let _inner = m.into_inner();
407407- assert_eq!(num_drops.load(Ordering::SeqCst), 0);
408408- }
409409- assert_eq!(num_drops.load(Ordering::SeqCst), 1);
410410- }
411411-412412- #[test]
413413- fn test_mutex_unsized() {
414414- let mutex: &Mutex<[i32]> = &Mutex::<_>::new([1, 2, 3]);
415415- {
416416- let b = &mut *mutex.lock();
417417- b[0] = 4;
418418- b[2] = 5;
419419- }
420420- let comp: &[i32] = &[4, 2, 5];
421421- assert_eq!(&*mutex.lock(), comp);
422422- }
423423-424424- #[test]
425425- fn test_mutex_force_lock() {
426426- let lock = Mutex::<_>::new(());
427427- mem::forget(lock.lock());
428428- unsafe {
429429- lock.force_unlock();
430430- }
431431- assert!(lock.try_lock().is_some());
432432- }
433433-434434- #[test]
435435- fn test_get_mut() {
436436- let mut m = Mutex::new(NonCopy(10));
437437- *m.get_mut() = NonCopy(20);
438438- assert_eq!(m.into_inner(), NonCopy(20));
439439- }
440440-441441- #[test]
442442- fn basic_multi_threaded() {
443443- use crate::loom::{self, Arc, thread};
444444-445445- #[allow(tail_expr_drop_order)]
446446- fn incr(lock: &Arc<Mutex<i32>>) -> thread::JoinHandle<()> {
447447- let lock = lock.clone();
448448- thread::spawn(move || {
449449- let mut lock = lock.lock();
450450- *lock += 1;
451451- })
452452- }
453453-454454- loom::model(|| {
455455- let lock = Arc::new(Mutex::new(0));
456456- let t1 = incr(&lock);
457457- let t2 = incr(&lock);
458458-459459- t1.join().unwrap();
460460- t2.join().unwrap();
461461-462462- thread::spawn(move || {
463463- let lock = lock.lock();
464464- assert_eq!(*lock, 2)
465465- });
466466- });
467467- }
468468-}
6161+// #[cfg(test)]
6262+// mod tests {
6363+// use core::fmt::Debug;
6464+// use std::{hint, mem};
6565+//
6666+// use super::*;
6767+// use crate::loom::{Arc, AtomicUsize};
6868+//
6969+// #[derive(Eq, PartialEq, Debug)]
7070+// struct NonCopy(i32);
7171+//
7272+// #[derive(Eq, PartialEq, Debug)]
7373+// struct NonCopyNeedsDrop(i32);
7474+//
7575+// impl Drop for NonCopyNeedsDrop {
7676+// fn drop(&mut self) {
7777+// hint::black_box(());
7878+// }
7979+// }
8080+//
8181+// #[test]
8282+// fn test_needs_drop() {
8383+// assert!(!mem::needs_drop::<NonCopy>());
8484+// assert!(mem::needs_drop::<NonCopyNeedsDrop>());
8585+// }
8686+//
8787+// #[test]
8888+// fn smoke() {
8989+// let m = Mutex::new(());
9090+// drop(m.lock());
9191+// drop(m.lock());
9292+// }
9393+//
9494+// #[test]
9595+// fn try_lock() {
9696+// let mutex = Mutex::<_>::new(42);
9797+//
9898+// // First lock succeeds
9999+// let a = mutex.try_lock();
100100+// assert_eq!(a.as_ref().map(|r| **r), Some(42));
101101+//
102102+// // Additional lock fails
103103+// let b = mutex.try_lock();
104104+// assert!(b.is_none());
105105+//
106106+// // After dropping lock, it succeeds again
107107+// drop(a);
108108+// let c = mutex.try_lock();
109109+// assert_eq!(c.as_ref().map(|r| **r), Some(42));
110110+// }
111111+//
112112+// #[test]
113113+// fn test_into_inner() {
114114+// let m = Mutex::<_>::new(NonCopy(10));
115115+// assert_eq!(m.into_inner(), NonCopy(10));
116116+// }
117117+//
118118+// #[test]
119119+// fn test_into_inner_drop() {
120120+// struct Foo(Arc<AtomicUsize>);
121121+// impl Drop for Foo {
122122+// fn drop(&mut self) {
123123+// self.0.fetch_add(1, Ordering::SeqCst);
124124+// }
125125+// }
126126+// let num_drops = Arc::new(AtomicUsize::new(0));
127127+// let m = Mutex::<_>::new(Foo(num_drops.clone()));
128128+// assert_eq!(num_drops.load(Ordering::SeqCst), 0);
129129+// {
130130+// let _inner = m.into_inner();
131131+// assert_eq!(num_drops.load(Ordering::SeqCst), 0);
132132+// }
133133+// assert_eq!(num_drops.load(Ordering::SeqCst), 1);
134134+// }
135135+//
136136+// #[test]
137137+// fn test_mutex_unsized() {
138138+// let mutex: &Mutex<[i32]> = &Mutex::<_>::new([1, 2, 3]);
139139+// {
140140+// let b = &mut *mutex.lock();
141141+// b[0] = 4;
142142+// b[2] = 5;
143143+// }
144144+// let comp: &[i32] = &[4, 2, 5];
145145+// assert_eq!(&*mutex.lock(), comp);
146146+// }
147147+//
148148+// #[test]
149149+// fn test_mutex_force_lock() {
150150+// let lock = Mutex::<_>::new(());
151151+// mem::forget(lock.lock());
152152+// unsafe {
153153+// lock.force_unlock();
154154+// }
155155+// assert!(lock.try_lock().is_some());
156156+// }
157157+//
158158+// #[test]
159159+// fn test_get_mut() {
160160+// let mut m = Mutex::new(NonCopy(10));
161161+// *m.get_mut() = NonCopy(20);
162162+// assert_eq!(m.into_inner(), NonCopy(20));
163163+// }
164164+//
165165+// #[test]
166166+// fn basic_multi_threaded() {
167167+// use crate::loom::{self, Arc, thread};
168168+//
169169+// #[allow(tail_expr_drop_order)]
170170+// fn incr(lock: &Arc<Mutex<i32>>) -> thread::JoinHandle<()> {
171171+// let lock = lock.clone();
172172+// thread::spawn(move || {
173173+// let mut lock = lock.lock();
174174+// *lock += 1;
175175+// })
176176+// }
177177+//
178178+// loom::model(|| {
179179+// let lock = Arc::new(Mutex::new(0));
180180+// let t1 = incr(&lock);
181181+// let t2 = incr(&lock);
182182+//
183183+// t1.join().unwrap();
184184+// t2.join().unwrap();
185185+//
186186+// thread::spawn(move || {
187187+// let lock = lock.lock();
188188+// assert_eq!(*lock, 2)
189189+// });
190190+// });
191191+// }
192192+// }
+19-8
libs/spin/src/once.rs
···991010use util::loom_const_fn;
11111212-use crate::loom::{AtomicU8, Ordering};
1212+use crate::loom::sync::atomic::{AtomicU8, Ordering};
13131414/// No initialization has run yet, and no thread is currently using the Once.
1515const STATUS_INCOMPLETE: u8 = 0;
···5151 }
52525353 pub fn state(&mut self) -> ExclusiveState {
5454- self.status.with_mut(|status| match *status {
5555- STATUS_INCOMPLETE => ExclusiveState::Incomplete,
5656- STATUS_POISONED => ExclusiveState::Poisoned,
5757- STATUS_COMPLETE => ExclusiveState::Complete,
5858- _ => unreachable!("invalid Once state"),
5959- })
5454+ cfg_if::cfg_if! {
5555+ if #[cfg(loom)] {
5656+ self.status.with_mut(|status| match *status {
5757+ STATUS_INCOMPLETE => ExclusiveState::Incomplete,
5858+ STATUS_POISONED => ExclusiveState::Poisoned,
5959+ STATUS_COMPLETE => ExclusiveState::Complete,
6060+ _ => unreachable!("invalid Once state"),
6161+ })
6262+ } else {
6363+ match *self.status.get_mut() {
6464+ STATUS_INCOMPLETE => ExclusiveState::Incomplete,
6565+ STATUS_POISONED => ExclusiveState::Poisoned,
6666+ STATUS_COMPLETE => ExclusiveState::Complete,
6767+ _ => unreachable!("invalid Once state"),
6868+ }
6969+ }
7070+ }
6071 }
61726273 /// # Panics
···208219 #[cfg(not(loom))]
209220 #[test]
210221 fn wait() {
211211- use crate::loom::{AtomicBool, Ordering};
222222+ use crate::loom::sync::atomic::{AtomicBool, Ordering};
212223213224 for _ in 0..50 {
214225 let val = AtomicBool::new(false);
+3-2
libs/spin/src/once_lock.rs
···1212use util::loom_const_fn;
13131414use super::Once;
1515-use crate::loom::UnsafeCell;
1515+use crate::loom::cell::UnsafeCell;
16161717/// A synchronization primitive which can be written to only once.
1818///
···319319 use std::sync::mpsc::channel;
320320321321 use super::*;
322322- use crate::loom::{AtomicUsize, Ordering, thread};
322322+ use crate::loom::sync::atomic::{AtomicUsize, Ordering};
323323+ use crate::loom::thread;
323324324325 fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
325326 thread::spawn(f).join().unwrap()
+2-1
libs/spin/src/remutex.rs
···15151616use util::loom_const_fn;
17171818-use crate::loom::{AtomicUsize, Ordering, UnsafeCell};
1818+use crate::loom::cell::UnsafeCell;
1919+use crate::loom::sync::atomic::{AtomicUsize, Ordering};
1920use crate::{Backoff, GuardNoSend};
20212122/// A mutex which can be recursively locked by a single thread.
+95-492
libs/spin/src/rw_lock.rs
···55// http://opensource.org/licenses/MIT>, at your option. This file may not be
66// copied, modified, or distributed except according to those terms.
7788-use core::ops::{Deref, DerefMut};
99-use core::ptr::NonNull;
1010-use core::{fmt, mem};
88+use core::sync::atomic::{AtomicUsize, Ordering};
1191212-use util::loom_const_fn;
1010+use lock_api::GuardSend;
13111412use crate::Backoff;
1515-use crate::loom::{AtomicUsize, Ordering, UnsafeCell};
16131714const READER: usize = 1 << 2;
1815const UPGRADED: usize = 1 << 1;
1916const WRITER: usize = 1;
20172121-pub struct RwLock<T: ?Sized> {
2222- lock: AtomicUsize,
2323- data: UnsafeCell<T>,
2424-}
2525-2626-/// RAII structure used to release the shared read access of a lock when
2727-/// dropped.
2828-#[clippy::has_significant_drop]
2929-#[must_use = "if unused the RwLock will immediately unlock"]
3030-pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
3131- // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
3232- // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
3333- // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
3434- // is preferable over `const* T` to allow for niche optimization.
3535- _data: NonNull<T>,
3636- rwlock: &'a RwLock<T>,
3737-}
3838-3939-/// RAII structure used to release the exclusive write access of a lock when
4040-/// dropped.
4141-#[clippy::has_significant_drop]
4242-#[must_use = "if unused the RwLock will immediately unlock"]
4343-pub struct RwLockWriteGuard<'a, T: ?Sized> {
4444- rwlock: &'a RwLock<T>,
4545-}
4646-4747-/// RAII structure used to release the upgradable read access of a lock when
4848-/// dropped.
4949-#[clippy::has_significant_drop]
5050-#[must_use = "if unused the RwLock will immediately unlock"]
5151-pub struct RwLockUpgradableReadGuard<'a, T: ?Sized + 'a> {
5252- // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
5353- // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
5454- // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
5555- // is preferable over `const* T` to allow for niche optimization.
5656- data: NonNull<T>,
5757- rwlock: &'a RwLock<T>,
5858-}
1818+pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
1919+pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
2020+pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;
2121+pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
59226060-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
6161-unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
6262-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
6363-unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
6464-6565-impl<T> RwLock<T> {
6666- loom_const_fn! {
6767- /// Creates a new instance of an `RwLock<T>` which is unlocked.
6868- #[inline]
6969- pub const fn new(val: T) -> RwLock<T> {
7070- RwLock {
7171- data: UnsafeCell::new(val),
7272- lock: AtomicUsize::new(0),
7373- }
7474- }
7575- }
7676-7777- /// Consumes this `RwLock`, returning the underlying data.
7878- #[inline]
7979- pub fn into_inner(self) -> T {
8080- self.data.into_inner()
8181- }
2323+pub struct RawRwLock {
2424+ lock: AtomicUsize,
8225}
83268484-impl<T: ?Sized> RwLock<T> {
8585- /// Creates a new `RwLockReadGuard` without checking if the lock is held.
8686- ///
8787- /// # Safety
8888- ///
8989- /// This method must only be called if the thread logically holds a read lock.
9090- ///
9191- /// This function does not increment the read count of the lock. Calling this function when a
9292- /// guard has already been produced is undefined behaviour unless the guard was forgotten
9393- /// with `mem::forget`.
9494- #[inline]
9595- pub unsafe fn make_read_guard_unchecked(&self) -> RwLockReadGuard<'_, T> {
9696- RwLockReadGuard {
9797- _data: self.data.with_mut(|data| {
9898- // Safety: ensured by caller
9999- unsafe { NonNull::new_unchecked(data) }
100100- }),
101101- rwlock: self,
102102- }
103103- }
104104-105105- /// Creates a new `RwLockReadGuard` without checking if the lock is held.
106106- ///
107107- /// # Safety
108108- ///
109109- /// This method must only be called if the thread logically holds a write lock.
110110- ///
111111- /// Calling this function when a guard has already been produced is undefined behaviour unless
112112- /// the guard was forgotten with `mem::forget`.
113113- #[inline]
114114- pub unsafe fn make_write_guard_unchecked(&self) -> RwLockWriteGuard<'_, T> {
115115- RwLockWriteGuard { rwlock: self }
116116- }
117117-118118- /// Locks this `RwLock` with shared read access, blocking the current thread
119119- /// until it can be acquired.
120120- ///
121121- /// The calling thread will be blocked until there are no more writers which
122122- /// hold the lock. There may be other readers currently inside the lock when
123123- /// this method returns.
124124- ///
125125- /// Note that attempts to recursively acquire a read lock on a `RwLock` when
126126- /// the current thread already holds one may result in a deadlock.
127127- ///
128128- /// Returns an RAII guard which will release this thread's shared access
129129- /// once it is dropped.
130130- #[inline]
131131- pub fn read(&self) -> RwLockReadGuard<'_, T> {
132132- self.lock_shared();
133133-134134- // SAFETY: The lock is held, as required.
135135- unsafe { self.make_read_guard_unchecked() }
136136- }
137137-138138- /// Attempts to acquire this `RwLock` with shared read access.
139139- ///
140140- /// If the access could not be granted at this time, then `None` is returned.
141141- /// Otherwise, an RAII guard is returned which will release the shared access
142142- /// when it is dropped.
143143- ///
144144- /// This function does not block.
145145- #[inline]
146146- pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
147147- if self.try_lock_shared() {
148148- // SAFETY: The lock is held, as required.
149149- Some(unsafe { self.make_read_guard_unchecked() })
150150- } else {
151151- None
152152- }
153153- }
154154-155155- fn acquire_reader(&self) -> usize {
156156- // An arbitrary cap that allows us to catch overflows long before they happen
157157- const MAX_READERS: usize = usize::MAX / READER / 2;
158158-159159- let value = self.lock.fetch_add(READER, Ordering::Acquire);
160160-161161- if value > MAX_READERS * READER {
162162- self.lock.fetch_sub(READER, Ordering::Relaxed);
163163- panic!("Too many lock readers, cannot safely proceed");
164164- } else {
165165- value
166166- }
167167- }
168168-169169- /// Locks this `RwLock` with exclusive write access, blocking the current
170170- /// thread until it can be acquired.
171171- ///
172172- /// This function will not return while other writers or other readers
173173- /// currently have access to the lock.
174174- ///
175175- /// Returns an RAII guard which will drop the write access of this `RwLock`
176176- /// when dropped.
177177- #[inline]
178178- pub fn write(&self) -> RwLockWriteGuard<'_, T> {
179179- self.lock_exclusive();
180180- // SAFETY: The lock is held, as required.
181181- unsafe { self.make_write_guard_unchecked() }
182182- }
183183-184184- /// Attempts to lock this `RwLock` with exclusive write access.
185185- ///
186186- /// If the lock could not be acquired at this time, then `None` is returned.
187187- /// Otherwise, an RAII guard is returned which will release the lock when
188188- /// it is dropped.
189189- ///
190190- /// This function does not block.
191191- #[inline]
192192- pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
193193- if self.try_lock_exclusive() {
194194- // SAFETY: The lock is held, as required.
195195- Some(unsafe { self.make_write_guard_unchecked() })
196196- } else {
197197- None
198198- }
199199- }
200200-201201- /// Returns a mutable reference to the underlying data.
202202- ///
203203- /// Since this call borrows the `RwLock` mutably, no actual locking needs to
204204- /// take place---the mutable borrow statically guarantees no locks exist.
205205- #[inline]
206206- pub fn get_mut(&mut self) -> &mut T {
207207- self.data.with_mut(|data| {
208208- // Safety: We hold a mutable reference to the RwLock so getting a mutable reference to the
209209- // data is safe
210210- unsafe { &mut *data }
211211- })
212212- }
213213-214214- /// Checks whether this `RwLock` is currently locked in any way.
215215- #[inline]
216216- pub fn is_locked(&self) -> bool {
217217- self.lock.load(Ordering::Relaxed) != 0
218218- }
2727+#[allow(clippy::undocumented_unsafe_blocks, reason = "TODO")]
2828+unsafe impl lock_api::RawRwLock for RawRwLock {
2929+ const INIT: Self = Self {
3030+ lock: AtomicUsize::new(0),
3131+ };
3232+ type GuardMarker = GuardSend;
2193322034 fn lock_shared(&self) {
22135 while !self.try_lock_shared() {
···23953 }
24054 }
241555656+ // fn try_lock_shared_weak(&self) -> bool {
5757+ // self.try_lock_shared()
5858+ // }
5959+6060+ unsafe fn unlock_shared(&self) {
6161+ debug_assert!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED) > 0);
6262+ self.lock.fetch_sub(READER, Ordering::Release);
6363+ }
6464+24265 fn lock_exclusive(&self) {
24366 let mut boff = Backoff::default();
24467 while !self.try_lock_exclusive_internal(false) {
···25073 self.try_lock_exclusive_internal(true)
25174 }
25275253253- fn try_lock_exclusive_internal(&self, strong: bool) -> bool {
254254- compare_exchange(
255255- &self.lock,
256256- 0,
257257- WRITER,
258258- Ordering::Acquire,
259259- Ordering::Relaxed,
260260- strong,
261261- )
262262- .is_ok()
263263- }
264264-265265- unsafe fn unlock_shared(&self) {
266266- debug_assert!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED) > 0);
267267- self.lock.fetch_sub(READER, Ordering::Release);
268268- }
7676+ // fn try_lock_exclusive_weak(&self) -> bool {
7777+ // self.try_lock_exclusive_internal(false)
7878+ // }
2697927080 unsafe fn unlock_exclusive(&self) {
27181 debug_assert_eq!(self.lock.load(Ordering::Relaxed) & WRITER, WRITER);
···27484 // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held.
27585 self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
27686 }
8787+}
27788278278- fn try_upgrade_internal(&self, strong: bool) -> bool {
279279- compare_exchange(
280280- &self.lock,
281281- UPGRADED,
282282- WRITER,
283283- Ordering::Acquire,
284284- Ordering::Relaxed,
285285- strong,
286286- )
287287- .is_ok()
8989+#[allow(clippy::undocumented_unsafe_blocks, reason = "TODO")]
9090+unsafe impl lock_api::RawRwLockUpgrade for RawRwLock {
9191+ fn lock_upgradable(&self) {
9292+ todo!()
9393+ }
9494+9595+ fn try_lock_upgradable(&self) -> bool {
9696+ todo!()
28897 }
9898+9999+ // fn try_lock_upgradable_weak(&self) -> bool {
100100+ // todo!()
101101+ // }
289102290103 unsafe fn unlock_upgradable(&self) {
291104 debug_assert_eq!(
···296109 }
297110298111 unsafe fn upgrade(&self) {
299299- while !self.try_upgrade_internal(false) {
112112+ while self.try_upgrade_internal(false) {
300113 #[cfg(loom)]
301114 crate::loom::thread::yield_now();
302115 core::hint::spin_loop();
···307120 self.try_upgrade_internal(true)
308121 }
309122310310- unsafe fn downgrade_upgradable(&self) {
123123+ // unsafe fn try_upgrade_weak(&self) -> bool {
124124+ // self.try_upgrade_internal(false)
125125+ // }
126126+}
127127+128128+#[allow(clippy::undocumented_unsafe_blocks, reason = "TODO")]
129129+unsafe impl lock_api::RawRwLockDowngrade for RawRwLock {
130130+ unsafe fn downgrade(&self) {
311131 // Reserve the read guard for ourselves
312132 self.acquire_reader();
313133314314- // Safety: we just acquired the lock
315315- unsafe {
316316- self.unlock_upgradable();
317317- }
318318- }
319319-}
134134+ debug_assert_eq!(self.lock.load(Ordering::Relaxed) & WRITER, WRITER);
320135321321-impl<T: Default> Default for RwLock<T> {
322322- #[inline]
323323- fn default() -> RwLock<T> {
324324- RwLock::new(Default::default())
136136+ // Writer is responsible for clearing both WRITER and UPGRADED bits.
137137+ // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held.
138138+ self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
325139 }
326140}
327141328328-impl<T> From<T> for RwLock<T> {
329329- #[inline]
330330- fn from(t: T) -> RwLock<T> {
331331- RwLock::new(t)
332332- }
333333-}
334334-335335-impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
336336- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337337- let mut d = f.debug_struct("RwLock");
338338- match self.try_read() {
339339- Some(guard) => d.field("data", &&*guard),
340340- None => {
341341- // Additional format_args! here is to remove quotes around <locked> in debug output.
342342- d.field("data", &format_args!("<locked>"))
343343- }
344344- };
345345- d.finish()
346346- }
347347-}
348348-349349-impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {}
350350-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
351351-unsafe impl<T: Sync + ?Sized> Sync for RwLockReadGuard<'_, T> {}
352352-353353-impl<'a, T: ?Sized + 'a> RwLockReadGuard<'a, T> {
354354- /// Returns a reference to the original reader-writer lock object.
355355- pub fn rwlock(s: &Self) -> &'a RwLock<T> {
356356- s.rwlock
357357- }
358358-}
359359-360360-impl<'a, T: ?Sized + 'a> Deref for RwLockReadGuard<'a, T> {
361361- type Target = T;
362362- #[inline]
363363- fn deref(&self) -> &T {
364364- self.rwlock.data.with(|data| {
365365- // Safety: RwLockReadGuard always holds a read lock, so obtaining an immutable reference
366366- // is safe
367367- unsafe { &*data }
368368- })
369369- }
370370-}
142142+#[allow(clippy::undocumented_unsafe_blocks, reason = "TODO")]
143143+unsafe impl lock_api::RawRwLockUpgradeDowngrade for RawRwLock {
144144+ unsafe fn downgrade_upgradable(&self) {
145145+ // Reserve the read guard for ourselves
146146+ self.acquire_reader();
371147372372-impl<'a, T: ?Sized + 'a> Drop for RwLockReadGuard<'a, T> {
373373- #[inline]
374374- fn drop(&mut self) {
375375- // Safety: An RwLockReadGuard always holds a shared lock.
148148+ // Safety: we just acquired the lock
376149 unsafe {
377377- self.rwlock.unlock_shared();
150150+ <Self as lock_api::RawRwLockUpgrade>::unlock_upgradable(self);
378151 }
379152 }
380380-}
381153382382-impl<'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for RwLockReadGuard<'a, T> {
383383- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384384- fmt::Debug::fmt(&**self, f)
385385- }
386386-}
387387-388388-impl<'a, T: fmt::Display + ?Sized + 'a> fmt::Display for RwLockReadGuard<'a, T> {
389389- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390390- (**self).fmt(f)
391391- }
392392-}
393393-394394-impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
395395-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
396396-unsafe impl<T: Sync + ?Sized> Sync for RwLockWriteGuard<'_, T> {}
397397-398398-impl<'a, T: ?Sized + 'a> RwLockWriteGuard<'a, T> {
399399- /// Returns a reference to the original reader-writer lock object.
400400- pub fn rwlock(s: &Self) -> &'a RwLock<T> {
401401- s.rwlock
402402- }
403403-404404- /// Atomically downgrades a write lock into a read lock without allowing any
405405- /// writers to take exclusive access of the lock in the meantime.
406406- ///
407407- /// Note that if there are any writers currently waiting to take the lock
408408- /// then other readers may not be able to acquire the lock even if it was
409409- /// downgraded.
410410- pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> {
411411- let rwlock = s.rwlock;
412412-413413- // Reserve the read guard for ourselves
414414- rwlock.acquire_reader();
415415-416416- debug_assert_eq!(rwlock.lock.load(Ordering::Relaxed) & WRITER, WRITER);
417417-418418- // Writer is responsible for clearing both WRITER and UPGRADED bits.
419419- // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held.
420420- rwlock
421421- .lock
422422- .fetch_and(!(WRITER | UPGRADED), Ordering::Release);
423423-424424- mem::forget(s);
425425- RwLockReadGuard {
426426- _data: rwlock.data.with_mut(|data| {
427427- // Safety: RwLockWriteGuard holds mutable access to the data
428428- unsafe { NonNull::new_unchecked(data) }
429429- }),
430430- rwlock,
431431- }
432432- }
433433-434434- /// Atomically downgrades a write lock into an upgradable read lock without allowing any
435435- /// writers to take exclusive access of the lock in the meantime.
436436- ///
437437- /// Note that if there are any writers currently waiting to take the lock
438438- /// then other readers may not be able to acquire the lock even if it was
439439- /// downgraded.
440440- pub fn downgrade_to_upgradable(s: Self) -> RwLockUpgradableReadGuard<'a, T> {
441441- let rwlock = s.rwlock;
442442-154154+ unsafe fn downgrade_to_upgradable(&self) {
443155 debug_assert_eq!(
444444- rwlock.lock.load(Ordering::Acquire) & (WRITER | UPGRADED),
156156+ self.lock.load(Ordering::Acquire) & (WRITER | UPGRADED),
445157 WRITER
446158 );
447159448160 // Reserve the read guard for ourselves
449449- rwlock.lock.store(UPGRADED, Ordering::Release);
161161+ self.lock.store(UPGRADED, Ordering::Release);
450162451451- debug_assert_eq!(rwlock.lock.load(Ordering::Relaxed) & WRITER, WRITER);
163163+ debug_assert_eq!(self.lock.load(Ordering::Relaxed) & WRITER, WRITER);
452164453165 // Writer is responsible for clearing both WRITER and UPGRADED bits.
454166 // The UPGRADED bit may be set if an upgradeable lock attempts an upgrade while this lock is held.
455455- rwlock
456456- .lock
457457- .fetch_and(!(WRITER | UPGRADED), Ordering::Release);
458458-459459- mem::forget(s);
460460- RwLockUpgradableReadGuard {
461461- data: rwlock.data.with_mut(|data| {
462462- // Safety: RwLockWriteGuard holds mutable access to the data
463463- unsafe { NonNull::new_unchecked(data) }
464464- }),
465465- rwlock,
466466- }
167167+ self.lock.fetch_and(!(WRITER | UPGRADED), Ordering::Release);
467168 }
468169}
469170470470-impl<'a, T: ?Sized + 'a> Deref for RwLockWriteGuard<'a, T> {
471471- type Target = T;
472472- #[inline]
473473- fn deref(&self) -> &T {
474474- self.rwlock.data.with(|data| {
475475- // Safety: RwLockWriteGuard always holds a read lock, so obtaining an immutable reference
476476- // is safe
477477- unsafe { &*data }
478478- })
479479- }
480480-}
171171+impl RawRwLock {
172172+ fn acquire_reader(&self) -> usize {
173173+ // An arbitrary cap that allows us to catch overflows long before they happen
174174+ const MAX_READERS: usize = usize::MAX / READER / 2;
481175482482-impl<'a, T: ?Sized + 'a> DerefMut for RwLockWriteGuard<'a, T> {
483483- #[inline]
484484- fn deref_mut(&mut self) -> &mut T {
485485- self.rwlock.data.with_mut(|data| {
486486- // Safety: RwLockWriteGuard always holds a write lock, so obtaining a mutable reference
487487- // is safe
488488- unsafe { &mut *data }
489489- })
490490- }
491491-}
176176+ let value = self.lock.fetch_add(READER, Ordering::Acquire);
492177493493-impl<'a, T: ?Sized + 'a> Drop for RwLockWriteGuard<'a, T> {
494494- #[inline]
495495- fn drop(&mut self) {
496496- // Safety: An RwLockWriteGuard always holds an exclusive lock.
497497- unsafe {
498498- self.rwlock.unlock_exclusive();
499499- }
500500- }
501501-}
502502-503503-impl<'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for RwLockWriteGuard<'a, T> {
504504- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505505- fmt::Debug::fmt(&**self, f)
506506- }
507507-}
508508-509509-impl<'a, T: fmt::Display + ?Sized + 'a> fmt::Display for RwLockWriteGuard<'a, T> {
510510- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511511- (**self).fmt(f)
512512- }
513513-}
514514-515515-impl<T: ?Sized> !Send for RwLockUpgradableReadGuard<'_, T> {}
516516-#[expect(clippy::undocumented_unsafe_blocks, reason = "")]
517517-unsafe impl<'a, T: ?Sized + Sync + 'a> Sync for RwLockUpgradableReadGuard<'a, T> {}
518518-519519-impl<'a, T: ?Sized + 'a> RwLockUpgradableReadGuard<'a, T> {
520520- /// Returns a reference to the original reader-writer lock object.
521521- pub fn rwlock(s: &Self) -> &'a RwLock<T> {
522522- s.rwlock
523523- }
524524-525525- /// Atomically upgrades an upgradable read lock lock into an exclusive write lock,
526526- /// blocking the current thread until it can be acquired.
527527- pub fn upgrade(s: Self) -> RwLockWriteGuard<'a, T> {
528528- // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
529529- unsafe {
530530- s.rwlock.upgrade();
531531- }
532532- let rwlock = s.rwlock;
533533- mem::forget(s);
534534- RwLockWriteGuard { rwlock }
535535- }
536536-537537- /// Tries to atomically upgrade an upgradable read lock into an exclusive write lock.
538538- ///
539539- /// # Errors
540540- ///
541541- /// If the access could not be granted at this time, then the current guard is returned.
542542- pub fn try_upgrade(s: Self) -> Result<RwLockWriteGuard<'a, T>, Self> {
543543- // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
544544- if unsafe { s.rwlock.try_upgrade() } {
545545- let rwlock = s.rwlock;
546546- mem::forget(s);
547547- Ok(RwLockWriteGuard { rwlock })
178178+ if value > MAX_READERS * READER {
179179+ self.lock.fetch_sub(READER, Ordering::Relaxed);
180180+ panic!("Too many lock readers, cannot safely proceed");
548181 } else {
549549- Err(s)
550550- }
551551- }
552552-553553- /// Atomically downgrades an upgradable read lock lock into a shared read lock
554554- /// without allowing any writers to take exclusive access of the lock in the
555555- /// meantime.
556556- ///
557557- /// Note that if there are any writers currently waiting to take the lock
558558- /// then other readers may not be able to acquire the lock even if it was
559559- /// downgraded.
560560- pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> {
561561- let data = s.data;
562562- // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
563563- unsafe {
564564- s.rwlock.downgrade_upgradable();
565565- }
566566- let rwlock = s.rwlock;
567567- mem::forget(s);
568568- RwLockReadGuard {
569569- _data: data,
570570- rwlock,
182182+ value
571183 }
572184 }
573573-}
574185575575-impl<'a, T: ?Sized + 'a> Deref for RwLockUpgradableReadGuard<'a, T> {
576576- type Target = T;
577577- #[inline]
578578- fn deref(&self) -> &T {
579579- self.rwlock.data.with(|data| {
580580- // Safety: RwLockUpgradableReadGuard always holds a read lock, so obtaining an immutable reference
581581- // is safe
582582- unsafe { &*data }
583583- })
186186+ fn try_lock_exclusive_internal(&self, strong: bool) -> bool {
187187+ compare_exchange(
188188+ &self.lock,
189189+ 0,
190190+ WRITER,
191191+ Ordering::Acquire,
192192+ Ordering::Relaxed,
193193+ strong,
194194+ )
195195+ .is_ok()
584196 }
585585-}
586197587587-impl<'a, T: ?Sized + 'a> Drop for RwLockUpgradableReadGuard<'a, T> {
588588- #[inline]
589589- fn drop(&mut self) {
590590- // Safety: An RwLockUpgradableReadGuard always holds an upgradable lock.
591591- unsafe {
592592- self.rwlock.unlock_upgradable();
593593- }
594594- }
595595-}
596596-597597-impl<'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for RwLockUpgradableReadGuard<'a, T> {
598598- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599599- fmt::Debug::fmt(&**self, f)
600600- }
601601-}
602602-603603-impl<'a, T: fmt::Display + ?Sized + 'a> fmt::Display for RwLockUpgradableReadGuard<'a, T> {
604604- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605605- (**self).fmt(f)
198198+ fn try_upgrade_internal(&self, strong: bool) -> bool {
199199+ compare_exchange(
200200+ &self.lock,
201201+ UPGRADED,
202202+ WRITER,
203203+ Ordering::Acquire,
204204+ Ordering::Relaxed,
205205+ strong,
206206+ )
207207+ .is_ok()
606208 }
607209}
608210···629231 use std::sync::mpsc::channel;
630232631233 use super::*;
632632- use crate::loom::{Arc, thread};
234234+ use crate::loom::sync::Arc;
235235+ use crate::loom::thread;
633236634237 #[derive(Eq, PartialEq, Debug)]
635238 struct NonCopy(i32);