diff options
| author | agri <[email protected]> | 2022-02-10 16:48:12 +0300 |
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:48:12 +0300 |
| commit | 2909866fbc652492b7d7cab3023cb19489dc4fd8 (patch) | |
| tree | b222e5ac2e2e98872661c51ccceee5da0d291e13 /library/cpp/threading/light_rw_lock | |
| parent | d3530b2692e400bd4d29bd4f07cafaee139164e7 (diff) | |
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/threading/light_rw_lock')
| -rw-r--r-- | library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp | 370 | ||||
| -rw-r--r-- | library/cpp/threading/light_rw_lock/bench/ya.make | 24 | ||||
| -rw-r--r-- | library/cpp/threading/light_rw_lock/lightrwlock.cpp | 224 | ||||
| -rw-r--r-- | library/cpp/threading/light_rw_lock/lightrwlock.h | 254 | ||||
| -rw-r--r-- | library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp | 236 | ||||
| -rw-r--r-- | library/cpp/threading/light_rw_lock/ut/ya.make | 14 | ||||
| -rw-r--r-- | library/cpp/threading/light_rw_lock/ya.make | 20 |
7 files changed, 571 insertions, 571 deletions
diff --git a/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp b/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp index 5e217c25ade..c3027ea5449 100644 --- a/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp +++ b/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp @@ -1,188 +1,188 @@ #include <library/cpp/threading/light_rw_lock/lightrwlock.h> -#include <util/random/random.h> - -#ifdef _linux_ -// Light rw lock is implemented only for linux - -using namespace NS_LightRWLock; - -#include <pthread.h> -#include <stdlib.h> -#include <stdio.h> - -#define LIGHT - -#ifdef RWSPINLOCK +#include <util/random/random.h> + +#ifdef _linux_ +// Light rw lock is implemented only for linux + +using namespace NS_LightRWLock; + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> + +#define LIGHT + +#ifdef RWSPINLOCK #include <library/cpp/lwtrace/rwspinlock.h> -#endif - -#define CHECK_LOGIC 1 -#define LOOPCOUNT 1000000 -#define RANRCOUNT 100 -#define THREADCOUNT 40 -#define WRITELOCKS 100 - -#if defined(_MSC_VER) -static int Y_FORCE_INLINE AtomicFetchAdd(volatile int& item, int value) { - return _InterlockedExchangeAdd((&item, value); -} -#elif defined(__GNUC__) -#else +#endif + +#define CHECK_LOGIC 1 +#define LOOPCOUNT 1000000 +#define RANRCOUNT 100 +#define THREADCOUNT 40 +#define WRITELOCKS 100 + +#if defined(_MSC_VER) +static int Y_FORCE_INLINE AtomicFetchAdd(volatile int& item, int value) { + return _InterlockedExchangeAdd((&item, value); +} +#elif defined(__GNUC__) +#else #error unsupported platform -#endif - -class TPosixRWLock { -public: - TPosixRWLock() { - } - - ~TPosixRWLock() { - pthread_rwlock_destroy(&rwlock); - } - - TPosixRWLock(const TPosixRWLock&) = delete; - void operator=(const TPosixRWLock&) = delete; - -private: - pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; - friend class TPosixRWShareLocker; - friend class TPosixRWExclusiveLocker; -}; - -#if defined(LIGHT) -TLightRWLock __attribute__((aligned(64))) rwlock; -#elif defined(POSIX) -TPosixRWLock rwlock; -#elif defined(RWSPINLOCK) -TRWSpinLock __attribute__((aligned(64))) rwlock; -#else -#error "define lock type" -#endif - -volatile __attribute__((aligned(64))) int checkIt = 0; -volatile int checkExcl = 0; - -class TPosixRWShareLocker { -public: - TPosixRWShareLocker(TPosixRWLock& lock) - : LockP_(&lock) - { - pthread_rwlock_rdlock(&LockP_->rwlock); - } - - ~TPosixRWShareLocker() { - pthread_rwlock_unlock(&LockP_->rwlock); - } - - TPosixRWShareLocker(const TPosixRWShareLocker&) = delete; - void operator=(const TPosixRWShareLocker&) = delete; - -private: - TPosixRWLock* LockP_; -}; - -class TPosixRWExclusiveLocker { -public: - TPosixRWExclusiveLocker(TPosixRWLock& lock) - : LockP_(&lock) - { - pthread_rwlock_wrlock(&LockP_->rwlock); - } - - ~TPosixRWExclusiveLocker() { - pthread_rwlock_unlock(&LockP_->rwlock); - } - TPosixRWExclusiveLocker(const TPosixRWExclusiveLocker&) = delete; - void operator=(const TPosixRWExclusiveLocker&) = delete; - -private: - TPosixRWLock* LockP_; -}; - -template <typename TLocker, bool excl> -static Y_FORCE_INLINE void Run() { - TLocker lockIt(rwlock); - -#if defined(CHECK_LOGIC) && CHECK_LOGIC - if (!excl && checkExcl == 1) { - printf("there is a bug\n"); - } - - int result = AtomicFetchAdd(checkIt, 1); - if (excl) - checkExcl = 1; - - if (excl && result > 1) - printf("there is a bug\n"); -#endif - - for (unsigned w = 0; w < RANRCOUNT; ++w) - RandomNumber<ui32>(); - -#if defined(CHECK_LOGIC) && CHECK_LOGIC - if (excl) - checkExcl = 0; - - AtomicFetchAdd(checkIt, -1); -#endif -} - -#ifdef LIGHT -static void* fast_thread_start(__attribute__((unused)) void* arg) { - for (unsigned q = 0; q < LOOPCOUNT; ++q) { - char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0; - if (excl) - Run<TLightWriteGuard, 1>(); - else - Run<TLightReadGuard, 0>(); - } - return NULL; -} -#endif - -#ifdef POSIX -static void* fast_thread_start(__attribute__((unused)) void* arg) { - for (unsigned q = 0; q < LOOPCOUNT; ++q) { - char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0; - if (excl) - Run<TPosixRWExclusiveLocker, 1>(); - else - Run<TPosixRWShareLocker, 0>(); - } - return NULL; -} -#endif - -#ifdef RWSPINLOCK -static void* fast_thread_start(__attribute__((unused)) void* arg) { - for (unsigned q = 0; q < LOOPCOUNT; ++q) { - char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0; - if (excl) - Run<TWriteSpinLockGuard, 1>(); - else - Run<TReadSpinLockGuard, 0>(); - } - return NULL; -} -#endif - -int main() { - pthread_t threads[THREADCOUNT]; - - for (unsigned q = 0; q < THREADCOUNT; ++q) { - pthread_create(&(threads[q]), NULL, &fast_thread_start, NULL); - } - - for (unsigned q = 0; q < THREADCOUNT; ++q) - pthread_join(threads[q], NULL); - - return 0; -} - -#else // !_linux_ - -int main() { - return 0; -} - -#endif +#endif + +class TPosixRWLock { +public: + TPosixRWLock() { + } + + ~TPosixRWLock() { + pthread_rwlock_destroy(&rwlock); + } + + TPosixRWLock(const TPosixRWLock&) = delete; + void operator=(const TPosixRWLock&) = delete; + +private: + pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + friend class TPosixRWShareLocker; + friend class TPosixRWExclusiveLocker; +}; + +#if defined(LIGHT) +TLightRWLock __attribute__((aligned(64))) rwlock; +#elif defined(POSIX) +TPosixRWLock rwlock; +#elif defined(RWSPINLOCK) +TRWSpinLock __attribute__((aligned(64))) rwlock; +#else +#error "define lock type" +#endif + +volatile __attribute__((aligned(64))) int checkIt = 0; +volatile int checkExcl = 0; + +class TPosixRWShareLocker { +public: + TPosixRWShareLocker(TPosixRWLock& lock) + : LockP_(&lock) + { + pthread_rwlock_rdlock(&LockP_->rwlock); + } + + ~TPosixRWShareLocker() { + pthread_rwlock_unlock(&LockP_->rwlock); + } + + TPosixRWShareLocker(const TPosixRWShareLocker&) = delete; + void operator=(const TPosixRWShareLocker&) = delete; + +private: + TPosixRWLock* LockP_; +}; + +class TPosixRWExclusiveLocker { +public: + TPosixRWExclusiveLocker(TPosixRWLock& lock) + : LockP_(&lock) + { + pthread_rwlock_wrlock(&LockP_->rwlock); + } + + ~TPosixRWExclusiveLocker() { + pthread_rwlock_unlock(&LockP_->rwlock); + } + TPosixRWExclusiveLocker(const TPosixRWExclusiveLocker&) = delete; + void operator=(const TPosixRWExclusiveLocker&) = delete; + +private: + TPosixRWLock* LockP_; +}; + +template <typename TLocker, bool excl> +static Y_FORCE_INLINE void Run() { + TLocker lockIt(rwlock); + +#if defined(CHECK_LOGIC) && CHECK_LOGIC + if (!excl && checkExcl == 1) { + printf("there is a bug\n"); + } + + int result = AtomicFetchAdd(checkIt, 1); + if (excl) + checkExcl = 1; + + if (excl && result > 1) + printf("there is a bug\n"); +#endif + + for (unsigned w = 0; w < RANRCOUNT; ++w) + RandomNumber<ui32>(); + +#if defined(CHECK_LOGIC) && CHECK_LOGIC + if (excl) + checkExcl = 0; + + AtomicFetchAdd(checkIt, -1); +#endif +} + +#ifdef LIGHT +static void* fast_thread_start(__attribute__((unused)) void* arg) { + for (unsigned q = 0; q < LOOPCOUNT; ++q) { + char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0; + if (excl) + Run<TLightWriteGuard, 1>(); + else + Run<TLightReadGuard, 0>(); + } + return NULL; +} +#endif + +#ifdef POSIX +static void* fast_thread_start(__attribute__((unused)) void* arg) { + for (unsigned q = 0; q < LOOPCOUNT; ++q) { + char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0; + if (excl) + Run<TPosixRWExclusiveLocker, 1>(); + else + Run<TPosixRWShareLocker, 0>(); + } + return NULL; +} +#endif + +#ifdef RWSPINLOCK +static void* fast_thread_start(__attribute__((unused)) void* arg) { + for (unsigned q = 0; q < LOOPCOUNT; ++q) { + char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0; + if (excl) + Run<TWriteSpinLockGuard, 1>(); + else + Run<TReadSpinLockGuard, 0>(); + } + return NULL; +} +#endif + +int main() { + pthread_t threads[THREADCOUNT]; + + for (unsigned q = 0; q < THREADCOUNT; ++q) { + pthread_create(&(threads[q]), NULL, &fast_thread_start, NULL); + } + + for (unsigned q = 0; q < THREADCOUNT; ++q) + pthread_join(threads[q], NULL); + + return 0; +} + +#else // !_linux_ + +int main() { + return 0; +} + +#endif diff --git a/library/cpp/threading/light_rw_lock/bench/ya.make b/library/cpp/threading/light_rw_lock/bench/ya.make index ed89e3a9b0a..7969b52a501 100644 --- a/library/cpp/threading/light_rw_lock/bench/ya.make +++ b/library/cpp/threading/light_rw_lock/bench/ya.make @@ -1,13 +1,13 @@ -PROGRAM(lightrwlock_test) - -OWNER(agri) - -SRCS( - lightrwlock_test.cpp -) - -PEERDIR( +PROGRAM(lightrwlock_test) + +OWNER(agri) + +SRCS( + lightrwlock_test.cpp +) + +PEERDIR( library/cpp/threading/light_rw_lock -) - -END() +) + +END() diff --git a/library/cpp/threading/light_rw_lock/lightrwlock.cpp b/library/cpp/threading/light_rw_lock/lightrwlock.cpp index 58456907d2b..fbb63fd47f7 100644 --- a/library/cpp/threading/light_rw_lock/lightrwlock.cpp +++ b/library/cpp/threading/light_rw_lock/lightrwlock.cpp @@ -1,113 +1,113 @@ -#include "lightrwlock.h" -#include <util/system/spinlock.h> - -#if defined(_linux_) - -using namespace NS_LightRWLock; - -void TLightRWLock::WaitForUntrappedShared() { - for (;;) { - for (ui32 i = 0; i < SpinCount_; ++i) { - SpinLockPause(); - - if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) - return; - } - - SequenceStore(UnshareFutex_, 1); - if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) { - AtomicStore(UnshareFutex_, 0); - return; - } - FutexWait(UnshareFutex_, 1); - } -} - -void TLightRWLock::WaitForExclusiveAndUntrappedShared() { - for (;;) { - for (ui32 i = 0; i < SpinCount_; ++i) { - SpinLockPause(); - - if (AtomicLoad(Counter_) >= 0) - goto try_to_get_lock; - if (AtomicLoad(TrappedFutex_) == 1) - goto skip_store_trapped; - } - - SequenceStore(TrappedFutex_, 1); - skip_store_trapped: - - if (AtomicLoad(Counter_) < 0) { - FutexWait(TrappedFutex_, 1); - } - - try_to_get_lock: - if (!AtomicSetBit(Counter_, 31)) - break; - } - - for (ui32 j = 0;; ++j) { - for (ui32 i = 0; i < SpinCount_; ++i) { - if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) - return; - - SpinLockPause(); - } - - SequenceStore(UnshareFutex_, 1); - - if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) { - AtomicStore(UnshareFutex_, 0); - return; - } - - FutexWait(UnshareFutex_, 1); - } -} - -void TLightRWLock::WaitForUntrappedAndAcquireRead() { - if (AtomicFetchAdd(Counter_, -1) < 0) - goto skip_lock_try; - - for (;;) { - again: - if (Y_UNLIKELY(AtomicFetchAdd(Counter_, 1) >= 0)) { - return; - } else { - if (AtomicFetchAdd(Counter_, -1) >= 0) - goto again; - } - - skip_lock_try: +#include "lightrwlock.h" +#include <util/system/spinlock.h> + +#if defined(_linux_) + +using namespace NS_LightRWLock; + +void TLightRWLock::WaitForUntrappedShared() { + for (;;) { + for (ui32 i = 0; i < SpinCount_; ++i) { + SpinLockPause(); + + if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) + return; + } + + SequenceStore(UnshareFutex_, 1); + if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) { + AtomicStore(UnshareFutex_, 0); + return; + } + FutexWait(UnshareFutex_, 1); + } +} + +void TLightRWLock::WaitForExclusiveAndUntrappedShared() { + for (;;) { + for (ui32 i = 0; i < SpinCount_; ++i) { + SpinLockPause(); + + if (AtomicLoad(Counter_) >= 0) + goto try_to_get_lock; + if (AtomicLoad(TrappedFutex_) == 1) + goto skip_store_trapped; + } + + SequenceStore(TrappedFutex_, 1); + skip_store_trapped: + + if (AtomicLoad(Counter_) < 0) { + FutexWait(TrappedFutex_, 1); + } + + try_to_get_lock: + if (!AtomicSetBit(Counter_, 31)) + break; + } + + for (ui32 j = 0;; ++j) { + for (ui32 i = 0; i < SpinCount_; ++i) { + if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) + return; + + SpinLockPause(); + } + + SequenceStore(UnshareFutex_, 1); + + if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) { + AtomicStore(UnshareFutex_, 0); + return; + } + + FutexWait(UnshareFutex_, 1); + } +} + +void TLightRWLock::WaitForUntrappedAndAcquireRead() { + if (AtomicFetchAdd(Counter_, -1) < 0) + goto skip_lock_try; + + for (;;) { + again: + if (Y_UNLIKELY(AtomicFetchAdd(Counter_, 1) >= 0)) { + return; + } else { + if (AtomicFetchAdd(Counter_, -1) >= 0) + goto again; + } + + skip_lock_try: if (AtomicLoad(UnshareFutex_) && (AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) { - SequenceStore(UnshareFutex_, 0); - FutexWake(UnshareFutex_, 1); - } - - for (;;) { - for (ui32 i = 0; i < SpinCount_; ++i) { - SpinLockPause(); - - if (AtomicLoad(Counter_) >= 0) - goto again; - if (AtomicLoad(TrappedFutex_) == 1) - goto skip_store_trapped; - } - - SequenceStore(TrappedFutex_, 1); - skip_store_trapped: - - if (AtomicLoad(Counter_) < 0) { - FutexWait(TrappedFutex_, 1); - if (AtomicLoad(Counter_) < 0) - goto again; - } else if (AtomicLoad(TrappedFutex_)) { - SequenceStore(TrappedFutex_, 0); - FutexWake(TrappedFutex_, 0x7fffffff); - } - break; - } - } -} - -#endif // _linux_ + SequenceStore(UnshareFutex_, 0); + FutexWake(UnshareFutex_, 1); + } + + for (;;) { + for (ui32 i = 0; i < SpinCount_; ++i) { + SpinLockPause(); + + if (AtomicLoad(Counter_) >= 0) + goto again; + if (AtomicLoad(TrappedFutex_) == 1) + goto skip_store_trapped; + } + + SequenceStore(TrappedFutex_, 1); + skip_store_trapped: + + if (AtomicLoad(Counter_) < 0) { + FutexWait(TrappedFutex_, 1); + if (AtomicLoad(Counter_) < 0) + goto again; + } else if (AtomicLoad(TrappedFutex_)) { + SequenceStore(TrappedFutex_, 0); + FutexWake(TrappedFutex_, 0x7fffffff); + } + break; + } + } +} + +#endif // _linux_ diff --git a/library/cpp/threading/light_rw_lock/lightrwlock.h b/library/cpp/threading/light_rw_lock/lightrwlock.h index 44117871695..931a1817bce 100644 --- a/library/cpp/threading/light_rw_lock/lightrwlock.h +++ b/library/cpp/threading/light_rw_lock/lightrwlock.h @@ -1,45 +1,45 @@ -#pragma once +#pragma once -#include <util/system/rwlock.h> +#include <util/system/rwlock.h> #include <util/system/sanitizers.h> - -#if defined(_linux_) -/* TLightRWLock is optimized for read lock and very fast lock/unlock switching. - Read lock increments counter. - Write lock sets highest bit of counter (makes counter negative). - - Whenever a thread tries to acquire read lock that thread increments - the counter. If the thread gets negative value of the counter right just - after the increment that means write lock was acquired in another thread. - In that case the thread decrements the counter back, wakes one thread on - UnshareFutex, waits on the TrappedFutex and then tries acquire read lock - from the beginning. - If the thread gets positive value of the counter after the increment - then read lock was successfully acquired and - the thread can proceed execution. - - Whenever a thread tries to acquire write lock that thread set the highest bit - of the counter. If the thread determine that the bit was set previously then - write lock was acquired in another thread. In that case the thread waits on - the TrappedFutex and then tries again from the beginning. - If the highest bit was successfully set then thread check if any read lock - exists at the moment. If so the thread waits on UnshareFutex. If there is - no more read locks then write lock was successfully acquired and the thread - can proceed execution. -*/ - -#include <linux/futex.h> + +#if defined(_linux_) +/* TLightRWLock is optimized for read lock and very fast lock/unlock switching. + Read lock increments counter. + Write lock sets highest bit of counter (makes counter negative). + + Whenever a thread tries to acquire read lock that thread increments + the counter. If the thread gets negative value of the counter right just + after the increment that means write lock was acquired in another thread. + In that case the thread decrements the counter back, wakes one thread on + UnshareFutex, waits on the TrappedFutex and then tries acquire read lock + from the beginning. + If the thread gets positive value of the counter after the increment + then read lock was successfully acquired and + the thread can proceed execution. + + Whenever a thread tries to acquire write lock that thread set the highest bit + of the counter. If the thread determine that the bit was set previously then + write lock was acquired in another thread. In that case the thread waits on + the TrappedFutex and then tries again from the beginning. + If the highest bit was successfully set then thread check if any read lock + exists at the moment. If so the thread waits on UnshareFutex. If there is + no more read locks then write lock was successfully acquired and the thread + can proceed execution. +*/ + +#include <linux/futex.h> #include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -namespace NS_LightRWLock { +#include <sys/syscall.h> +#include <errno.h> + +namespace NS_LightRWLock { static int Y_FORCE_INLINE AtomicFetchAdd(volatile int& item, int value) { return __atomic_fetch_add(&item, value, __ATOMIC_SEQ_CST); } - -#if defined(_x86_64_) || defined(_i386_) - + +#if defined(_x86_64_) || defined(_i386_) + static char Y_FORCE_INLINE AtomicSetBit(volatile int& item, unsigned bit) { char ret; __asm__ __volatile__( @@ -54,7 +54,7 @@ namespace NS_LightRWLock { return ret; } - + static char Y_FORCE_INLINE AtomicClearBit(volatile int& item, unsigned bit) { char ret; __asm__ __volatile__( @@ -69,22 +69,22 @@ namespace NS_LightRWLock { return ret; } - - -#else - + + +#else + static char Y_FORCE_INLINE AtomicSetBit(volatile int& item, unsigned bit) { int prev = __atomic_fetch_or(&item, 1 << bit, __ATOMIC_SEQ_CST); return (prev & (1 << bit)) != 0 ? 1 : 0; } - + static char Y_FORCE_INLINE AtomicClearBit(volatile int& item, unsigned bit) { int prev = __atomic_fetch_and(&item, ~(1 << bit), __ATOMIC_SEQ_CST); return (prev & (1 << bit)) != 0 ? 1 : 0; } #endif - + #if defined(_x86_64_) || defined(_i386_) || defined (__aarch64__) || defined (__powerpc64__) static bool AtomicLockHighByte(volatile int& item) { union TA { @@ -98,23 +98,23 @@ namespace NS_LightRWLock { __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); } -#endif - +#endif + template <typename TInt> static void Y_FORCE_INLINE AtomicStore(volatile TInt& var, TInt value) { __atomic_store_n(&var, value, __ATOMIC_RELEASE); } - + template <typename TInt> static void Y_FORCE_INLINE SequenceStore(volatile TInt& var, TInt value) { __atomic_store_n(&var, value, __ATOMIC_SEQ_CST); } - + template <typename TInt> static TInt Y_FORCE_INLINE AtomicLoad(const volatile TInt& var) { return __atomic_load_n(&var, __ATOMIC_ACQUIRE); } - + static void Y_FORCE_INLINE FutexWait(volatile int& fvar, int value) { for (;;) { int result = @@ -126,9 +126,9 @@ namespace NS_LightRWLock { continue; Y_FAIL("futex error"); } - } - } - + } + } + static void Y_FORCE_INLINE FutexWake(volatile int& fvar, int amount) { const int result = syscall(SYS_futex, &fvar, FUTEX_WAKE_PRIVATE, amount, NULL, NULL, 0); @@ -136,85 +136,85 @@ namespace NS_LightRWLock { Y_FAIL("futex error"); } -} - -class alignas(64) TLightRWLock { -public: - TLightRWLock(ui32 spinCount = 10) - : Counter_(0) - , TrappedFutex_(0) - , UnshareFutex_(0) - , SpinCount_(spinCount) +} + +class alignas(64) TLightRWLock { +public: + TLightRWLock(ui32 spinCount = 10) + : Counter_(0) + , TrappedFutex_(0) + , UnshareFutex_(0) + , SpinCount_(spinCount) { } - - TLightRWLock(const TLightRWLock&) = delete; - void operator=(const TLightRWLock&) = delete; - - Y_FORCE_INLINE void AcquireWrite() { - using namespace NS_LightRWLock; - - if (AtomicLockHighByte(Counter_)) { - if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) - return; - return WaitForUntrappedShared(); - } - WaitForExclusiveAndUntrappedShared(); - } - - Y_FORCE_INLINE void AcquireRead() { - using namespace NS_LightRWLock; - - if (Y_LIKELY(AtomicFetchAdd(Counter_, 1) >= 0)) - return; - WaitForUntrappedAndAcquireRead(); - } - - Y_FORCE_INLINE void ReleaseWrite() { - using namespace NS_LightRWLock; - - AtomicClearBit(Counter_, 31); - if (AtomicLoad(TrappedFutex_)) { - SequenceStore(TrappedFutex_, 0); - FutexWake(TrappedFutex_, 0x7fffffff); - } - } - - Y_FORCE_INLINE void ReleaseRead() { - using namespace NS_LightRWLock; - - if (Y_LIKELY(AtomicFetchAdd(Counter_, -1) >= 0)) - return; - if (!AtomicLoad(UnshareFutex_)) - return; - if ((AtomicLoad(Counter_) & 0x7fffffff) == 0) { - SequenceStore(UnshareFutex_, 0); - FutexWake(UnshareFutex_, 1); - } - } - -private: - volatile int Counter_; - volatile int TrappedFutex_; - volatile int UnshareFutex_; - const ui32 SpinCount_; - - void WaitForUntrappedShared(); - void WaitForExclusiveAndUntrappedShared(); - void WaitForUntrappedAndAcquireRead(); -}; - -#else - -class TLightRWLock: public TRWMutex { -public: + + TLightRWLock(const TLightRWLock&) = delete; + void operator=(const TLightRWLock&) = delete; + + Y_FORCE_INLINE void AcquireWrite() { + using namespace NS_LightRWLock; + + if (AtomicLockHighByte(Counter_)) { + if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) + return; + return WaitForUntrappedShared(); + } + WaitForExclusiveAndUntrappedShared(); + } + + Y_FORCE_INLINE void AcquireRead() { + using namespace NS_LightRWLock; + + if (Y_LIKELY(AtomicFetchAdd(Counter_, 1) >= 0)) + return; + WaitForUntrappedAndAcquireRead(); + } + + Y_FORCE_INLINE void ReleaseWrite() { + using namespace NS_LightRWLock; + + AtomicClearBit(Counter_, 31); + if (AtomicLoad(TrappedFutex_)) { + SequenceStore(TrappedFutex_, 0); + FutexWake(TrappedFutex_, 0x7fffffff); + } + } + + Y_FORCE_INLINE void ReleaseRead() { + using namespace NS_LightRWLock; + + if (Y_LIKELY(AtomicFetchAdd(Counter_, -1) >= 0)) + return; + if (!AtomicLoad(UnshareFutex_)) + return; + if ((AtomicLoad(Counter_) & 0x7fffffff) == 0) { + SequenceStore(UnshareFutex_, 0); + FutexWake(UnshareFutex_, 1); + } + } + +private: + volatile int Counter_; + volatile int TrappedFutex_; + volatile int UnshareFutex_; + const ui32 SpinCount_; + + void WaitForUntrappedShared(); + void WaitForExclusiveAndUntrappedShared(); + void WaitForUntrappedAndAcquireRead(); +}; + +#else + +class TLightRWLock: public TRWMutex { +public: TLightRWLock() { } TLightRWLock(ui32) { } -}; - -#endif - -using TLightReadGuard = TReadGuardBase<TLightRWLock>; -using TLightWriteGuard = TWriteGuardBase<TLightRWLock>; +}; + +#endif + +using TLightReadGuard = TReadGuardBase<TLightRWLock>; +using TLightWriteGuard = TWriteGuardBase<TLightRWLock>; diff --git a/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp b/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp index 3ed4bf68faa..e82063d959f 100644 --- a/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp +++ b/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp @@ -1,122 +1,122 @@ #include <library/cpp/threading/light_rw_lock/lightrwlock.h> #include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include <util/system/atomic.h> +#include <util/random/random.h> +#include <util/system/atomic.h> #include <util/thread/pool.h> - -class TRWMutexTest: public TTestBase { - UNIT_TEST_SUITE(TRWMutexTest); - UNIT_TEST(TestReaders) - UNIT_TEST(TestReadersWriters) - UNIT_TEST_SUITE_END(); - - struct TSharedData { - TSharedData() - : writersIn(0) - , readersIn(0) - , failed(false) - { - } - - TAtomic writersIn; - TAtomic readersIn; - - bool failed; - - TLightRWLock mutex; - }; - - class TThreadTask: public IObjectInQueue { - public: - using PFunc = void (TThreadTask::*)(void); - - TThreadTask(PFunc func, TSharedData& data, size_t id, size_t total) - : Func_(func) - , Data_(data) - , Id_(id) - , Total_(total) - { - } - - void Process(void*) override { - THolder<TThreadTask> This(this); - - (this->*Func_)(); - } - -#define FAIL_ASSERT(cond) \ - if (!(cond)) { \ - Data_.failed = true; \ - } - void RunReaders() { - Data_.mutex.AcquireRead(); - - AtomicIncrement(Data_.readersIn); - usleep(100); - FAIL_ASSERT(Data_.readersIn == long(Total_)); - usleep(100); - AtomicDecrement(Data_.readersIn); - - Data_.mutex.ReleaseRead(); - } - - void RunReadersWriters() { - if (Id_ % 2 == 0) { - for (size_t i = 0; i < 10; ++i) { - Data_.mutex.AcquireRead(); - - AtomicIncrement(Data_.readersIn); - FAIL_ASSERT(Data_.writersIn == 0); - usleep(RandomNumber<ui32>() % 5); - AtomicDecrement(Data_.readersIn); - - Data_.mutex.ReleaseRead(); - } - } else { - for (size_t i = 0; i < 10; ++i) { - Data_.mutex.AcquireWrite(); - - AtomicIncrement(Data_.writersIn); - FAIL_ASSERT(Data_.readersIn == 0 && Data_.writersIn == 1); - usleep(RandomNumber<ui32>() % 5); - AtomicDecrement(Data_.writersIn); - - Data_.mutex.ReleaseWrite(); - } - } - } -#undef FAIL_ASSERT - - private: - PFunc Func_; - TSharedData& Data_; - size_t Id_; - size_t Total_; - }; - -private: -#define RUN_CYCLE(what, count) \ - Q_.Start(count); \ - for (size_t i = 0; i < count; ++i) { \ - UNIT_ASSERT(Q_.Add(new TThreadTask(&TThreadTask::what, Data_, i, count))); \ - } \ - Q_.Stop(); \ - bool b = Data_.failed; \ - Data_.failed = false; \ - UNIT_ASSERT(!b); - - void TestReaders() { - RUN_CYCLE(RunReaders, 1); - } - - void TestReadersWriters() { - RUN_CYCLE(RunReadersWriters, 1); - } - -#undef RUN_CYCLE -private: - TSharedData Data_; + +class TRWMutexTest: public TTestBase { + UNIT_TEST_SUITE(TRWMutexTest); + UNIT_TEST(TestReaders) + UNIT_TEST(TestReadersWriters) + UNIT_TEST_SUITE_END(); + + struct TSharedData { + TSharedData() + : writersIn(0) + , readersIn(0) + , failed(false) + { + } + + TAtomic writersIn; + TAtomic readersIn; + + bool failed; + + TLightRWLock mutex; + }; + + class TThreadTask: public IObjectInQueue { + public: + using PFunc = void (TThreadTask::*)(void); + + TThreadTask(PFunc func, TSharedData& data, size_t id, size_t total) + : Func_(func) + , Data_(data) + , Id_(id) + , Total_(total) + { + } + + void Process(void*) override { + THolder<TThreadTask> This(this); + + (this->*Func_)(); + } + +#define FAIL_ASSERT(cond) \ + if (!(cond)) { \ + Data_.failed = true; \ + } + void RunReaders() { + Data_.mutex.AcquireRead(); + + AtomicIncrement(Data_.readersIn); + usleep(100); + FAIL_ASSERT(Data_.readersIn == long(Total_)); + usleep(100); + AtomicDecrement(Data_.readersIn); + + Data_.mutex.ReleaseRead(); + } + + void RunReadersWriters() { + if (Id_ % 2 == 0) { + for (size_t i = 0; i < 10; ++i) { + Data_.mutex.AcquireRead(); + + AtomicIncrement(Data_.readersIn); + FAIL_ASSERT(Data_.writersIn == 0); + usleep(RandomNumber<ui32>() % 5); + AtomicDecrement(Data_.readersIn); + + Data_.mutex.ReleaseRead(); + } + } else { + for (size_t i = 0; i < 10; ++i) { + Data_.mutex.AcquireWrite(); + + AtomicIncrement(Data_.writersIn); + FAIL_ASSERT(Data_.readersIn == 0 && Data_.writersIn == 1); + usleep(RandomNumber<ui32>() % 5); + AtomicDecrement(Data_.writersIn); + + Data_.mutex.ReleaseWrite(); + } + } + } +#undef FAIL_ASSERT + + private: + PFunc Func_; + TSharedData& Data_; + size_t Id_; + size_t Total_; + }; + +private: +#define RUN_CYCLE(what, count) \ + Q_.Start(count); \ + for (size_t i = 0; i < count; ++i) { \ + UNIT_ASSERT(Q_.Add(new TThreadTask(&TThreadTask::what, Data_, i, count))); \ + } \ + Q_.Stop(); \ + bool b = Data_.failed; \ + Data_.failed = false; \ + UNIT_ASSERT(!b); + + void TestReaders() { + RUN_CYCLE(RunReaders, 1); + } + + void TestReadersWriters() { + RUN_CYCLE(RunReadersWriters, 1); + } + +#undef RUN_CYCLE +private: + TSharedData Data_; TThreadPool Q_; -}; - -UNIT_TEST_SUITE_REGISTRATION(TRWMutexTest) +}; + +UNIT_TEST_SUITE_REGISTRATION(TRWMutexTest) diff --git a/library/cpp/threading/light_rw_lock/ut/ya.make b/library/cpp/threading/light_rw_lock/ut/ya.make index 9b1a54d7ecd..92928b837c2 100644 --- a/library/cpp/threading/light_rw_lock/ut/ya.make +++ b/library/cpp/threading/light_rw_lock/ut/ya.make @@ -1,9 +1,9 @@ UNITTEST_FOR(library/cpp/threading/light_rw_lock) - + OWNER(agri) - -SRCS( - rwlock_ut.cpp -) - -END() + +SRCS( + rwlock_ut.cpp +) + +END() diff --git a/library/cpp/threading/light_rw_lock/ya.make b/library/cpp/threading/light_rw_lock/ya.make index e86fd422238..a196fb85886 100644 --- a/library/cpp/threading/light_rw_lock/ya.make +++ b/library/cpp/threading/light_rw_lock/ya.make @@ -1,10 +1,10 @@ -LIBRARY() - -OWNER(agri) - -SRCS( - lightrwlock.cpp - lightrwlock.h -) - -END() +LIBRARY() + +OWNER(agri) + +SRCS( + lightrwlock.cpp + lightrwlock.h +) + +END() |
