aboutsummaryrefslogtreecommitdiffstats
path: root/yt/yt/core/misc/atomic_ptr.h
blob: 89104ad7bba9c29b89f0adc2d4b0f3463521b889 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#pragma once

#include "hazard_ptr.h"
#include "intrusive_ptr.h"

namespace NYT {

////////////////////////////////////////////////////////////////////////////////

// Overload for TIntrusivePtr<T> MakeStrong(T* p).
template <class T>
TIntrusivePtr<T> MakeStrong(const THazardPtr<T>& ptr);

////////////////////////////////////////////////////////////////////////////////

//! Holds an atomic pointer to an instance of ref-counted type |T| enabling concurrent
//! read and write access.
template <class T, bool EnableAcquireHazard = false>
class TAtomicPtr
{
public:
    TAtomicPtr() = default;
    TAtomicPtr(std::nullptr_t);
    explicit TAtomicPtr(TIntrusivePtr<T> other);
    TAtomicPtr(TAtomicPtr&& other);

    ~TAtomicPtr();

    TAtomicPtr& operator=(TIntrusivePtr<T> other);
    TAtomicPtr& operator=(std::nullptr_t);

    void Reset();

    //! Acquires a hazard pointer.
    /*!
     *
     *  Returning a hazard pointer avoids contention on ref-counter in read-heavy scenarios.
     *  The user, however, must not keep this hazard pointer alive for longer
     *  than needed. Currently there are limits on the number of HPs that a thread
     *  may concurrently maintain.
     */
    THazardPtr<T> AcquireHazard() const;

    //! Attempts to acquire an intrusive pointer.
    //! May return null in case of a race.
    TIntrusivePtr<T> AcquireWeak() const;

    //! Acquires an intrusive pointer.
    TIntrusivePtr<T> Acquire() const;

    TAtomicPtr<T, EnableAcquireHazard> Exchange(TIntrusivePtr<T> other);
    void Store(TIntrusivePtr<T> other);

    TAtomicPtr<T, EnableAcquireHazard> SwapIfCompare(THazardPtr<T>& compare, TIntrusivePtr<T> target);
    bool SwapIfCompare(T* comparePtr, TIntrusivePtr<T> target);
    bool SwapIfCompare(const TIntrusivePtr<T>& compare, TIntrusivePtr<T> target);
    bool SwapIfCompare(const TIntrusivePtr<T>& compare, TIntrusivePtr<T>* target);

    explicit operator bool() const;

private:
    explicit TAtomicPtr(T* ptr);

    template <class T_, bool EnableAcquireHazard_>
    friend bool operator==(const TAtomicPtr<T_, EnableAcquireHazard_>& lhs, const TIntrusivePtr<T_>& rhs);

    template <class T_, bool EnableAcquireHazard_>
    friend bool operator==(const TIntrusivePtr<T_>& lhs, const TAtomicPtr<T_, EnableAcquireHazard_>& rhs);

    std::atomic<T*> Ptr_ = nullptr;

    THazardPtr<T> DoAcquireHazard() const;
    void Drop(T* ptr);
};

////////////////////////////////////////////////////////////////////////////////

} // namespace NYT

#define ATOMIC_PTR_INL_H_
#include "atomic_ptr-inl.h"
#undef ATOMIC_PTR_INL_H_