atomic_intrusive_ptr.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #pragma once
  2. #include "intrusive_ptr.h"
  3. #include <util/system/compiler.h>
  4. #if defined(_lsan_enabled_) || defined(_asan_enabled_)
  5. #include <util/system/spinlock.h>
  6. #endif
  7. namespace NYT {
  8. ////////////////////////////////////////////////////////////////////////////////
  9. //! Atomic pointer with split reference counting.
  10. /*
  11. * \see https://github.com/facebook/folly/blob/main/folly/concurrency/AtomicSharedPtr.h
  12. */
  13. template <class T>
  14. class TAtomicIntrusivePtr
  15. {
  16. public:
  17. using TUnderlying = T;
  18. using element_type = T;
  19. TAtomicIntrusivePtr() = default;
  20. TAtomicIntrusivePtr(std::nullptr_t);
  21. explicit TAtomicIntrusivePtr(TIntrusivePtr<T> other);
  22. TAtomicIntrusivePtr(TAtomicIntrusivePtr&& other);
  23. ~TAtomicIntrusivePtr();
  24. TAtomicIntrusivePtr& operator=(TIntrusivePtr<T> other);
  25. TAtomicIntrusivePtr& operator=(std::nullptr_t);
  26. TIntrusivePtr<T> Acquire() const;
  27. TIntrusivePtr<T> Exchange(TIntrusivePtr<T> other);
  28. void Store(TIntrusivePtr<T> other);
  29. void Reset();
  30. using TRawPtr = std::conditional_t<std::is_const_v<T>, const void*, void*>;
  31. bool CompareAndSwap(TRawPtr& comparePtr, T* target);
  32. bool CompareAndSwap(TRawPtr& comparePtr, TIntrusivePtr<T> target);
  33. //! Result is only suitable for comparison, not dereference.
  34. TRawPtr Get() const;
  35. //! Result is only suitable for comparison, not dereference.
  36. TRawPtr get() const;
  37. explicit operator bool() const;
  38. private:
  39. template <class U>
  40. friend bool operator==(const TAtomicIntrusivePtr<U>& lhs, const TIntrusivePtr<U>& rhs);
  41. template <class U>
  42. friend bool operator==(const TIntrusivePtr<U>& lhs, const TAtomicIntrusivePtr<U>& rhs);
  43. template <class U>
  44. friend bool operator!=(const TAtomicIntrusivePtr<U>& lhs, const TIntrusivePtr<U>& rhs);
  45. template <class U>
  46. friend bool operator!=(const TIntrusivePtr<U>& lhs, const TAtomicIntrusivePtr<U>& rhs);
  47. #if defined(_lsan_enabled_) || defined(_asan_enabled_)
  48. ::TSpinLock Lock_;
  49. TIntrusivePtr<T> Ptr_;
  50. #else
  51. // Keeps packed pointer (localRefCount, objectPtr).
  52. // Atomic ptr holds N references, where N = ReservedRefCount - localRefCount.
  53. // LocalRefCount is incremented in Acquire method.
  54. // When localRefCount exceeds ReservedRefCount / 2 a new portion of refs are required globally.
  55. // This field is marked mutable in order to make Acquire const-qualified in accordance to its semantics.
  56. mutable std::atomic<TPackedPtr> Ptr_ = 0;
  57. constexpr static int CounterBits = PackedPtrTagBits;
  58. constexpr static int ReservedRefCount = (1 << CounterBits) - 1;
  59. // Consume ref if ownership is transferred.
  60. static TPackedPtr AcquireObject(T* obj, bool consumeRef = false);
  61. static void ReleaseObject(TPackedPtr packedPtr);
  62. static void DoRelease(T* obj, int refs);
  63. #endif
  64. };
  65. ////////////////////////////////////////////////////////////////////////////////
  66. } // namespace NYT
  67. #define ATOMIC_INTRUSIVE_PTR_INL_H_
  68. #include "atomic_intrusive_ptr-inl.h"
  69. #undef ATOMIC_INTRUSIVE_PTR_INL_H_