123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- #pragma once
- #include <util/generic/cast.h>
- #include <util/generic/ptr.h>
- #include <util/generic/utility.h>
- #include <library/cpp/deprecated/atomic/atomic.h>
- #include <util/system/guard.h>
- #include <util/system/spinlock.h>
- #include <util/system/yassert.h>
- namespace NHotSwapPrivate {
-
- class TWriterLock {
- public:
-
- void Acquire() noexcept;
- void Release() noexcept;
- void WaitAllReaders() const noexcept;
- private:
- TAtomic ReadersCount = 0;
- };
- }
- template <class T, class Ops = TDefaultIntrusivePtrOps<T>>
- class THotSwap {
- public:
- using TPtr = TIntrusivePtr<T, Ops>;
- public:
- THotSwap() noexcept {
- }
- explicit THotSwap(T* p) noexcept {
- AtomicStore(p);
- }
- explicit THotSwap(const TPtr& p) noexcept
- : THotSwap(p.Get())
- {
- }
- THotSwap(const THotSwap& p) noexcept
- : THotSwap(p.AtomicLoad())
- {
- }
- THotSwap(THotSwap&& other) noexcept {
- DoSwap(RawPtr, other.RawPtr);
- }
- ~THotSwap() noexcept {
- AtomicStore(nullptr);
- }
- THotSwap& operator=(const THotSwap& p) noexcept {
- AtomicStore(p.AtomicLoad());
- return *this;
- }
-
-
-
- TPtr AtomicLoad() const noexcept {
- const TAtomicBase lockIndex = GetLockIndex();
- auto guard = Guard(WriterLocks[lockIndex]);
- return GetRawPtr();
- }
-
-
-
- void AtomicStore(T* p) noexcept;
-
-
-
- void AtomicStore(const TPtr& p) noexcept {
- AtomicStore(p.Get());
- }
- private:
- T* GetRawPtr() const noexcept {
- return reinterpret_cast<T*>(AtomicGet(RawPtr));
- }
- TAtomicBase GetLockIndex() const noexcept {
- return AtomicGet(LockIndex);
- }
- TAtomicBase SwitchLockIndex() noexcept;
- void SwitchRawPtr(T* from, T* to) noexcept;
- void WaitReaders() noexcept;
- private:
- TAtomic RawPtr = 0;
- static_assert(sizeof(TAtomic) == sizeof(T*), "TAtomic can't represent a pointer value");
- TAdaptiveLock UpdateMutex;
- mutable NHotSwapPrivate::TWriterLock WriterLocks[2];
- TAtomic LockIndex = 0;
- };
- template <class T, class Ops>
- void THotSwap<T, Ops>::AtomicStore(T* p) noexcept {
- TPtr oldPtr;
- with_lock (UpdateMutex) {
- oldPtr = GetRawPtr();
- SwitchRawPtr(oldPtr.Get(), p);
- Y_ASSERT(!oldPtr || oldPtr.RefCount() > 0);
-
- WaitReaders();
-
- }
- }
- template <class T, class Ops>
- TAtomicBase THotSwap<T, Ops>::SwitchLockIndex() noexcept {
- const TAtomicBase prevIndex = AtomicGet(LockIndex);
- Y_ASSERT(prevIndex == 0 || prevIndex == 1);
- AtomicSet(LockIndex, prevIndex ^ 1);
- return prevIndex;
- }
- template <class T, class Ops>
- void THotSwap<T, Ops>::WaitReaders() noexcept {
- WriterLocks[SwitchLockIndex()].WaitAllReaders();
- WriterLocks[SwitchLockIndex()].WaitAllReaders();
- }
- template <class T, class Ops>
- void THotSwap<T, Ops>::SwitchRawPtr(T* from, T* to) noexcept {
- if (to)
- Ops::Ref(to);
- AtomicSet(RawPtr, reinterpret_cast<TAtomicBase>(to));
- if (from)
- Ops::UnRef(from);
- }
|