1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef SkWeakRefCnt_DEFINED
9cb93a386Sopenharmony_ci#define SkWeakRefCnt_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h"
12cb93a386Sopenharmony_ci#include <atomic>
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ci/** \class SkWeakRefCnt
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci    SkWeakRefCnt is the base class for objects that may be shared by multiple
17cb93a386Sopenharmony_ci    objects. When an existing strong owner wants to share a reference, it calls
18cb93a386Sopenharmony_ci    ref(). When a strong owner wants to release its reference, it calls
19cb93a386Sopenharmony_ci    unref(). When the shared object's strong reference count goes to zero as
20cb93a386Sopenharmony_ci    the result of an unref() call, its (virtual) weak_dispose method is called.
21cb93a386Sopenharmony_ci    It is an error for the destructor to be called explicitly (or via the
22cb93a386Sopenharmony_ci    object going out of scope on the stack or calling delete) if
23cb93a386Sopenharmony_ci    getRefCnt() > 1.
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ci    In addition to strong ownership, an owner may instead obtain a weak
26cb93a386Sopenharmony_ci    reference by calling weak_ref(). A call to weak_ref() must be balanced by a
27cb93a386Sopenharmony_ci    call to weak_unref(). To obtain a strong reference from a weak reference,
28cb93a386Sopenharmony_ci    call try_ref(). If try_ref() returns true, the owner's pointer is now also
29cb93a386Sopenharmony_ci    a strong reference on which unref() must be called. Note that this does not
30cb93a386Sopenharmony_ci    affect the original weak reference, weak_unref() must still be called. When
31cb93a386Sopenharmony_ci    the weak reference count goes to zero, the object is deleted. While the
32cb93a386Sopenharmony_ci    weak reference count is positive and the strong reference count is zero the
33cb93a386Sopenharmony_ci    object still exists, but will be in the disposed state. It is up to the
34cb93a386Sopenharmony_ci    object to define what this means.
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    Note that a strong reference implicitly implies a weak reference. As a
37cb93a386Sopenharmony_ci    result, it is allowable for the owner of a strong ref to call try_ref().
38cb93a386Sopenharmony_ci    This will have the same effect as calling ref(), but may be more expensive.
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    Example:
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci    SkWeakRefCnt myRef = strongRef.weak_ref();
43cb93a386Sopenharmony_ci    ... // strongRef.unref() may or may not be called
44cb93a386Sopenharmony_ci    if (myRef.try_ref()) {
45cb93a386Sopenharmony_ci        ... // use myRef
46cb93a386Sopenharmony_ci        myRef.unref();
47cb93a386Sopenharmony_ci    } else {
48cb93a386Sopenharmony_ci        // myRef is in the disposed state
49cb93a386Sopenharmony_ci    }
50cb93a386Sopenharmony_ci    myRef.weak_unref();
51cb93a386Sopenharmony_ci*/
52cb93a386Sopenharmony_ciclass SK_API SkWeakRefCnt : public SkRefCnt {
53cb93a386Sopenharmony_cipublic:
54cb93a386Sopenharmony_ci    /** Default construct, initializing the reference counts to 1.
55cb93a386Sopenharmony_ci        The strong references collectively hold one weak reference. When the
56cb93a386Sopenharmony_ci        strong reference count goes to zero, the collectively held weak
57cb93a386Sopenharmony_ci        reference is released.
58cb93a386Sopenharmony_ci    */
59cb93a386Sopenharmony_ci    SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {}
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    /** Destruct, asserting that the weak reference count is 1.
62cb93a386Sopenharmony_ci    */
63cb93a386Sopenharmony_ci    ~SkWeakRefCnt() override {
64cb93a386Sopenharmony_ci#ifdef SK_DEBUG
65cb93a386Sopenharmony_ci        SkASSERT(getWeakCnt() == 1);
66cb93a386Sopenharmony_ci        fWeakCnt.store(0, std::memory_order_relaxed);
67cb93a386Sopenharmony_ci#endif
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci#ifdef SK_DEBUG
71cb93a386Sopenharmony_ci    /** Return the weak reference count. */
72cb93a386Sopenharmony_ci    int32_t getWeakCnt() const {
73cb93a386Sopenharmony_ci        return fWeakCnt.load(std::memory_order_relaxed);
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci#endif
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ciprivate:
78cb93a386Sopenharmony_ci    /** If fRefCnt is 0, returns 0.
79cb93a386Sopenharmony_ci     *  Otherwise increments fRefCnt, acquires, and returns the old value.
80cb93a386Sopenharmony_ci     */
81cb93a386Sopenharmony_ci    int32_t atomic_conditional_acquire_strong_ref() const {
82cb93a386Sopenharmony_ci        int32_t prev = fRefCnt.load(std::memory_order_relaxed);
83cb93a386Sopenharmony_ci        do {
84cb93a386Sopenharmony_ci            if (0 == prev) {
85cb93a386Sopenharmony_ci                break;
86cb93a386Sopenharmony_ci            }
87cb93a386Sopenharmony_ci        } while(!fRefCnt.compare_exchange_weak(prev, prev+1, std::memory_order_acquire,
88cb93a386Sopenharmony_ci                                                             std::memory_order_relaxed));
89cb93a386Sopenharmony_ci        return prev;
90cb93a386Sopenharmony_ci    }
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_cipublic:
93cb93a386Sopenharmony_ci    /** Creates a strong reference from a weak reference, if possible. The
94cb93a386Sopenharmony_ci        caller must already be an owner. If try_ref() returns true the owner
95cb93a386Sopenharmony_ci        is in posession of an additional strong reference. Both the original
96cb93a386Sopenharmony_ci        reference and new reference must be properly unreferenced. If try_ref()
97cb93a386Sopenharmony_ci        returns false, no strong reference could be created and the owner's
98cb93a386Sopenharmony_ci        reference is in the same state as before the call.
99cb93a386Sopenharmony_ci    */
100cb93a386Sopenharmony_ci    bool SK_WARN_UNUSED_RESULT try_ref() const {
101cb93a386Sopenharmony_ci        if (atomic_conditional_acquire_strong_ref() != 0) {
102cb93a386Sopenharmony_ci            // Acquire barrier (L/SL), if not provided above.
103cb93a386Sopenharmony_ci            // Prevents subsequent code from happening before the increment.
104cb93a386Sopenharmony_ci            return true;
105cb93a386Sopenharmony_ci        }
106cb93a386Sopenharmony_ci        return false;
107cb93a386Sopenharmony_ci    }
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci    /** Increment the weak reference count. Must be balanced by a call to
110cb93a386Sopenharmony_ci        weak_unref().
111cb93a386Sopenharmony_ci    */
112cb93a386Sopenharmony_ci    void weak_ref() const {
113cb93a386Sopenharmony_ci        SkASSERT(getRefCnt() > 0);
114cb93a386Sopenharmony_ci        SkASSERT(getWeakCnt() > 0);
115cb93a386Sopenharmony_ci        // No barrier required.
116cb93a386Sopenharmony_ci        (void)fWeakCnt.fetch_add(+1, std::memory_order_relaxed);
117cb93a386Sopenharmony_ci    }
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    /** Decrement the weak reference count. If the weak reference count is 1
120cb93a386Sopenharmony_ci        before the decrement, then call delete on the object. Note that if this
121cb93a386Sopenharmony_ci        is the case, then the object needs to have been allocated via new, and
122cb93a386Sopenharmony_ci        not on the stack.
123cb93a386Sopenharmony_ci    */
124cb93a386Sopenharmony_ci    void weak_unref() const {
125cb93a386Sopenharmony_ci        SkASSERT(getWeakCnt() > 0);
126cb93a386Sopenharmony_ci        // A release here acts in place of all releases we "should" have been doing in ref().
127cb93a386Sopenharmony_ci        if (1 == fWeakCnt.fetch_add(-1, std::memory_order_acq_rel)) {
128cb93a386Sopenharmony_ci            // Like try_ref(), the acquire is only needed on success, to make sure
129cb93a386Sopenharmony_ci            // code in internal_dispose() doesn't happen before the decrement.
130cb93a386Sopenharmony_ci#ifdef SK_DEBUG
131cb93a386Sopenharmony_ci            // so our destructor won't complain
132cb93a386Sopenharmony_ci            fWeakCnt.store(1, std::memory_order_relaxed);
133cb93a386Sopenharmony_ci#endif
134cb93a386Sopenharmony_ci            this->INHERITED::internal_dispose();
135cb93a386Sopenharmony_ci        }
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    /** Returns true if there are no strong references to the object. When this
139cb93a386Sopenharmony_ci        is the case all future calls to try_ref() will return false.
140cb93a386Sopenharmony_ci    */
141cb93a386Sopenharmony_ci    bool weak_expired() const {
142cb93a386Sopenharmony_ci        return fRefCnt.load(std::memory_order_relaxed) == 0;
143cb93a386Sopenharmony_ci    }
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ciprotected:
146cb93a386Sopenharmony_ci    /** Called when the strong reference count goes to zero. This allows the
147cb93a386Sopenharmony_ci        object to free any resources it may be holding. Weak references may
148cb93a386Sopenharmony_ci        still exist and their level of allowed access to the object is defined
149cb93a386Sopenharmony_ci        by the object's class.
150cb93a386Sopenharmony_ci    */
151cb93a386Sopenharmony_ci    virtual void weak_dispose() const {
152cb93a386Sopenharmony_ci    }
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ciprivate:
155cb93a386Sopenharmony_ci    /** Called when the strong reference count goes to zero. Calls weak_dispose
156cb93a386Sopenharmony_ci        on the object and releases the implicit weak reference held
157cb93a386Sopenharmony_ci        collectively by the strong references.
158cb93a386Sopenharmony_ci    */
159cb93a386Sopenharmony_ci    void internal_dispose() const override {
160cb93a386Sopenharmony_ci        weak_dispose();
161cb93a386Sopenharmony_ci        weak_unref();
162cb93a386Sopenharmony_ci    }
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci    /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */
165cb93a386Sopenharmony_ci    mutable std::atomic<int32_t> fWeakCnt;
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    using INHERITED = SkRefCnt;
168cb93a386Sopenharmony_ci};
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci#endif
171