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