#pragma once #ifndef RW_SPIN_LOCK_INL_H_ #error "Direct inclusion of this file is not allowed, include rw_spin_lock.h" // For the sake of sane code completion. #include "rw_spin_lock.h" #endif #undef RW_SPIN_LOCK_INL_H_ #include "spin_wait.h" namespace NYT::NThreading { //////////////////////////////////////////////////////////////////////////////// inline void TReaderWriterSpinLock::AcquireReader() noexcept { if (TryAcquireReader()) { return; } AcquireReaderSlow(); } inline void TReaderWriterSpinLock::AcquireReaderForkFriendly() noexcept { if (TryAcquireReaderForkFriendly()) { return; } AcquireReaderForkFriendlySlow(); } inline void TReaderWriterSpinLock::ReleaseReader() noexcept { auto prevValue = Value_.fetch_sub(ReaderDelta, std::memory_order::release); Y_ASSERT((prevValue & ~WriterMask) != 0); NDetail::RecordSpinLockReleased(); } inline void TReaderWriterSpinLock::AcquireWriter() noexcept { if (TryAcquireWriter()) { return; } AcquireWriterSlow(); } inline void TReaderWriterSpinLock::ReleaseWriter() noexcept { auto prevValue = Value_.fetch_and(~WriterMask, std::memory_order::release); Y_ASSERT(prevValue & WriterMask); NDetail::RecordSpinLockReleased(); } inline bool TReaderWriterSpinLock::IsLocked() const noexcept { return Value_.load() != UnlockedValue; } inline bool TReaderWriterSpinLock::IsLockedByReader() const noexcept { return Value_.load() >= ReaderDelta; } inline bool TReaderWriterSpinLock::IsLockedByWriter() const noexcept { return (Value_.load() & WriterMask) != 0; } inline bool TReaderWriterSpinLock::TryAcquireReader() noexcept { auto oldValue = Value_.fetch_add(ReaderDelta, std::memory_order::acquire); if ((oldValue & WriterMask) != 0) { Value_.fetch_sub(ReaderDelta, std::memory_order::relaxed); return false; } NDetail::RecordSpinLockAcquired(); return true; } inline bool TReaderWriterSpinLock::TryAndTryAcquireReader() noexcept { auto oldValue = Value_.load(std::memory_order::relaxed); if ((oldValue & WriterMask) != 0) { return false; } return TryAcquireReader(); } inline bool TReaderWriterSpinLock::TryAcquireReaderForkFriendly() noexcept { auto oldValue = Value_.load(std::memory_order::relaxed); if ((oldValue & WriterMask) != 0) { return false; } auto newValue = oldValue + ReaderDelta; bool acquired = Value_.compare_exchange_weak(oldValue, newValue, std::memory_order::acquire); NDetail::RecordSpinLockAcquired(acquired); return acquired; } inline bool TReaderWriterSpinLock::TryAcquireWriter() noexcept { auto expected = UnlockedValue; bool acquired = Value_.compare_exchange_weak(expected, WriterMask, std::memory_order::acquire); NDetail::RecordSpinLockAcquired(acquired); return acquired; } inline bool TReaderWriterSpinLock::TryAndTryAcquireWriter() noexcept { auto oldValue = Value_.load(std::memory_order::relaxed); if (oldValue != UnlockedValue) { return false; } return TryAcquireWriter(); } //////////////////////////////////////////////////////////////////////////////// template void TReaderSpinlockTraits::Acquire(T* spinlock) { spinlock->AcquireReader(); } template void TReaderSpinlockTraits::Release(T* spinlock) { spinlock->ReleaseReader(); } //////////////////////////////////////////////////////////////////////////////// template void TForkFriendlyReaderSpinlockTraits::Acquire(T* spinlock) { spinlock->AcquireReaderForkFriendly(); } template void TForkFriendlyReaderSpinlockTraits::Release(T* spinlock) { spinlock->ReleaseReader(); } //////////////////////////////////////////////////////////////////////////////// template void TWriterSpinlockTraits::Acquire(T* spinlock) { spinlock->AcquireWriter(); } template void TWriterSpinlockTraits::Release(T* spinlock) { spinlock->ReleaseWriter(); } //////////////////////////////////////////////////////////////////////////////// template auto ReaderGuard(const T& lock) { return TReaderGuard(lock); } template auto ReaderGuard(const T* lock) { return TReaderGuard(lock); } template auto ForkFriendlyReaderGuard(const T& lock) { return TGuard>(lock); } template auto ForkFriendlyReaderGuard(const T* lock) { return TGuard>(lock); } template auto WriterGuard(const T& lock) { return TWriterGuard(lock); } template auto WriterGuard(const T* lock) { return TWriterGuard(lock); } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT::NThreading