diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/lwtrace/rwspinlock.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/lwtrace/rwspinlock.h')
-rw-r--r-- | library/cpp/lwtrace/rwspinlock.h | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/library/cpp/lwtrace/rwspinlock.h b/library/cpp/lwtrace/rwspinlock.h new file mode 100644 index 00000000000..7c518ec49e4 --- /dev/null +++ b/library/cpp/lwtrace/rwspinlock.h @@ -0,0 +1,88 @@ +#pragma once + +#include <util/system/spinlock.h> + +// State can be one of: +// 0) [NOT_USED] State = 0: +// * any reader can acquire lock (State += 2: -> READING) +// * one writer can acquire lock (State = -1: -> WRITING) +// 1) [READING] even number: +// * State/2 = number of active readers +// * no writers are waiting +// * any reader can aqcuire lock (State += 2: -> READING) +// * active readers can release lock (State -= 2) +// * one writer can acquire lock (State += 1: -> WAITING) +// 2) [WAITING] odd number > 0: +// * (State-1)/2 = number of active readers +// * no more readers/writers can acquire lock +// * active readers can release lock (State -= 2: -> WAITING) +// * exactly one writer is waiting for active readers to release lock +// * if no more active readers left (State == 1) waiting writer acquires lock (State = -1: -> WRITING) +// 3) [WRITING] State = -1 +// * exactly one active writer +// * no active readers +// * no more readers/writers can acquire lock +// * writer can release lock (State = 0: -> READING) + +struct TRWSpinLock { + TAtomic State; // must be initialized by 'TRWSpinLock myLock = {0};' construction + + void Init() noexcept { + State = 0; + } + + void AcquireRead() noexcept { + while (true) { + TAtomic a = AtomicGet(State); + if ((a & 1) == 0 && AtomicCas(&State, a + 2, a)) { + break; + } + SpinLockPause(); + } + } + + void ReleaseRead() noexcept { + AtomicAdd(State, -2); + } + + void AcquireWrite() noexcept { + while (true) { + TAtomic a = AtomicGet(State); + if ((a & 1) == 0 && AtomicCas(&State, a + 1, a)) { + break; + } + SpinLockPause(); + } + + while (!AtomicCas(&State, TAtomicBase(-1), 1)) { + SpinLockPause(); + } + } + + void ReleaseWrite() noexcept { + AtomicSet(State, 0); + } +}; + +struct TRWSpinLockReadOps { + static inline void Acquire(TRWSpinLock* t) noexcept { + t->AcquireRead(); + } + + static inline void Release(TRWSpinLock* t) noexcept { + t->ReleaseRead(); + } +}; + +struct TRWSpinLockWriteOps { + static inline void Acquire(TRWSpinLock* t) noexcept { + t->AcquireWrite(); + } + + static inline void Release(TRWSpinLock* t) noexcept { + t->ReleaseWrite(); + } +}; + +using TReadSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockReadOps>; +using TWriteSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockWriteOps>; |