diff --git a/src/lock/api.rs b/src/lock/api.rs index 59ec3406302..f229d96532e 100644 --- a/src/lock/api.rs +++ b/src/lock/api.rs @@ -23,7 +23,8 @@ pub unsafe trait RawLock: Default + Send + Sync { /// /// # Safety /// - /// `unlock()` should be called with the token given by the corresponding `lock()`. + /// - `self` must be a an acquired lock. + /// - `token` must be from a [`RawLock::lock`] or [`RawTryLock::unlock`] call to `self`. unsafe fn unlock(&self, token: Self::Token); } @@ -31,19 +32,16 @@ pub unsafe trait RawLock: Default + Send + Sync { /// /// # Safety /// -/// Implementations of this trait must ensure that the lock is actually exclusive: a lock can't be -/// acquired while the lock is already locked. +/// See [`RawLock`] for safety requirements. /// -/// Also, `try_lock()`, when successful, should return a token that can be used for -/// `RawLock::unlock`. +/// Also, [`RawTryLock::try_lock`] should return a token that can be used for [`RawLock::unlock`]. pub unsafe trait RawTryLock: RawLock { /// Tries to acquire the raw lock. fn try_lock(&self) -> Result; } /// A type-safe lock. -#[repr(C)] -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Lock { inner: L, data: UnsafeCell, @@ -54,19 +52,6 @@ pub struct Lock { // SATEFY: threads can only access `&mut T` via the lock, and `L` is `Sync`. unsafe impl Sync for Lock {} -impl Default for Lock -where - L: Default, -{ - // Manual impl for minimum trait bound. - fn default() -> Self { - Self { - inner: L::default(), - data: UnsafeCell::default(), - } - } -} - impl Lock { /// Creates a new lock. pub fn new(data: T) -> Self { diff --git a/src/lock/seqlock.rs b/src/lock/seqlock.rs index 5ccd77af0cf..4d7bcf0d750 100644 --- a/src/lock/seqlock.rs +++ b/src/lock/seqlock.rs @@ -56,7 +56,7 @@ impl RawSeqLock { /// # Safety /// /// - `self` must be a an acquired writer's lock. - /// - `seq` must be the be the value returned from the corresponding of the `write_lock()`. + /// - `seq` must be from the most recent [`SeqLock::write_lock`] call on `self`. pub unsafe fn write_unlock(&self, seq: usize) { self.seq.store(seq.wrapping_add(2), Release); } @@ -88,6 +88,7 @@ impl RawSeqLock { /// # Safety /// /// - `seq` must be even. + // No need to require `self` to be a read lock, as the sequence number is enough to validate. pub unsafe fn upgrade(&self, seq: usize) -> bool { if self .seq @@ -223,7 +224,7 @@ impl Drop for ReadGuard<'_, T> { fn drop(&mut self) { // HACK(@jeehoonkang): we really need linear type here: // https://github.com/rust-lang/rfcs/issues/814 - panic!("`seqlock::ReadGuard` should never drop. Use `ReadGuard::finish()` instead."); + panic!("`seqlock::ReadGuard` should never drop. Use `ReadGuard::finish` instead."); } } diff --git a/src/lockfree/list.rs b/src/lockfree/list.rs index 6877d5b46e6..d841d868458 100644 --- a/src/lockfree/list.rs +++ b/src/lockfree/list.rs @@ -21,7 +21,7 @@ pub struct Node { /// Sorted singly linked list. /// /// Use-after-free will be caused when an unprotected guard is used, as the lifetime of returned -/// elements are linked to that of the guard in the same way a `Shared<'g,T>` is. +/// elements are linked to that of the guard in the same way a [`Shared`] is. #[derive(Debug)] pub struct List { head: Atomic>, diff --git a/src/lockfree/queue.rs b/src/lockfree/queue.rs index e6060cf3955..5ffaed82c6e 100644 --- a/src/lockfree/queue.rs +++ b/src/lockfree/queue.rs @@ -66,8 +66,6 @@ impl Queue { }); loop { - guard.repin(); - // We push onto the tail, so we'll start optimistically by looking there first. let tail = self.tail.load(Acquire, guard); @@ -97,6 +95,7 @@ impl Queue { } Err(e) => new = e.new, } + guard.repin(); } } @@ -105,8 +104,6 @@ impl Queue { /// Returns `None` if the queue is observed to be empty. pub fn try_pop(&self, guard: &mut Guard) -> Option { loop { - guard.repin(); - let head = self.head.load(Acquire, guard); let next = unsafe { head.deref() }.next.load(Acquire, guard); @@ -125,7 +122,8 @@ impl Queue { // than that of current head. We relase that view to the head with the below CAS, // ensuring that the index of the new head is less than or equal to that of the tail. // - // Note: similar reasoning is done in SC memory regarding index of head and tail. + // Note: this reasoning is also done in SC memory regarding index of head and tail, + // albeit simpler. if self .head .compare_exchange(head, next, Release, Relaxed, guard) @@ -150,6 +148,7 @@ impl Queue { return Some(result); } + guard.repin(); } } }