atomic_intrusive_ptr.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #pragma once
  2. #include "intrusive_ptr.h"
  3. namespace NYT {
  4. ////////////////////////////////////////////////////////////////////////////////
  5. // Atomic ptr based on https://github.com/facebook/folly/blob/main/folly/concurrency/AtomicSharedPtr.h
  6. // Operators * and -> for TAtomicIntrusivePtr are useless because it is not safe to work with atomic ptr such way
  7. // Safe usage is to convert to TIntrusivePtr.
  8. // Max TAtomicIntrusivePtr count per object is (2**16 = 2**32 / 2**16).
  9. template <class T>
  10. class TAtomicIntrusivePtr
  11. {
  12. public:
  13. TAtomicIntrusivePtr() = default;
  14. TAtomicIntrusivePtr(std::nullptr_t);
  15. explicit TAtomicIntrusivePtr(TIntrusivePtr<T> other);
  16. TAtomicIntrusivePtr(TAtomicIntrusivePtr&& other);
  17. ~TAtomicIntrusivePtr();
  18. TAtomicIntrusivePtr& operator=(TIntrusivePtr<T> other);
  19. TAtomicIntrusivePtr& operator=(std::nullptr_t);
  20. TIntrusivePtr<T> Acquire() const;
  21. TIntrusivePtr<T> Exchange(TIntrusivePtr<T> other);
  22. void Store(TIntrusivePtr<T> other);
  23. void Reset();
  24. using TRawPtr = std::conditional_t<std::is_const_v<T>, const void*, void*>;
  25. bool CompareAndSwap(TRawPtr& comparePtr, T* target);
  26. bool CompareAndSwap(TRawPtr& comparePtr, TIntrusivePtr<T> target);
  27. // Result is suitable only for comparison. Not dereference.
  28. TRawPtr Get() const;
  29. explicit operator bool() const;
  30. private:
  31. template <class U>
  32. friend bool operator==(const TAtomicIntrusivePtr<U>& lhs, const TIntrusivePtr<U>& rhs);
  33. template <class U>
  34. friend bool operator==(const TIntrusivePtr<U>& lhs, const TAtomicIntrusivePtr<U>& rhs);
  35. template <class U>
  36. friend bool operator!=(const TAtomicIntrusivePtr<U>& lhs, const TIntrusivePtr<U>& rhs);
  37. template <class U>
  38. friend bool operator!=(const TIntrusivePtr<U>& lhs, const TAtomicIntrusivePtr<U>& rhs);
  39. // Keeps packed pointer (localRefCount, objectPtr).
  40. // Atomic ptr holds N references, where N = ReservedRefCount - localRefCount.
  41. // LocalRefCount is incremented in Acquire method.
  42. // When localRefCount exceeds ReservedRefCount / 2 a new portion of refs are required globally.
  43. // This field is marked mutable in order to make Acquire const-qualified in accordance to its semantics.
  44. mutable std::atomic<TPackedPtr> Ptr_ = 0;
  45. constexpr static int CounterBits = PackedPtrTagBits;
  46. constexpr static int ReservedRefCount = (1 << CounterBits) - 1;
  47. // Consume ref if ownership is transferred.
  48. // AcquireObject(ptr.Release(), true)
  49. // AcquireObject(ptr.Get(), false)
  50. static TPackedPtr AcquireObject(T* obj, bool consumeRef = false);
  51. static void ReleaseObject(TPackedPtr packedPtr);
  52. static void DoRelease(T* obj, int refs);
  53. };
  54. ////////////////////////////////////////////////////////////////////////////////
  55. } // namespace NYT
  56. #define ATOMIC_INTRUSIVE_PTR_INL_H_
  57. #include "atomic_intrusive_ptr-inl.h"
  58. #undef ATOMIC_INTRUSIVE_PTR_INL_H_