1/* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#ifndef RefCounted_h 22#define RefCounted_h 23 24#include "wtf/Assertions.h" 25#include "wtf/FastAllocBase.h" 26#include "wtf/Noncopyable.h" 27#include "wtf/OwnPtr.h" 28#include "wtf/ThreadRestrictionVerifier.h" 29#include "wtf/UnusedParam.h" 30#include "wtf/WTFExport.h" 31 32namespace WTF { 33 34#ifdef NDEBUG 35#define CHECK_REF_COUNTED_LIFECYCLE 0 36#else 37#define CHECK_REF_COUNTED_LIFECYCLE 1 38#endif 39 40// This base class holds the non-template methods and attributes. 41// The RefCounted class inherits from it reducing the template bloat 42// generated by the compiler (technique called template hoisting). 43class WTF_EXPORT RefCountedBase { 44public: 45 void ref() 46 { 47#if CHECK_REF_COUNTED_LIFECYCLE 48 // Start thread verification as soon as the ref count gets to 2. This 49 // heuristic reflects the fact that items are often created on one thread 50 // and then given to another thread to be used. 51 // FIXME: Make this restriction tigher. Especially as we move to more 52 // common methods for sharing items across threads like CrossThreadCopier.h 53 // We should be able to add a "detachFromThread" method to make this explicit. 54 if (m_refCount == 1) 55 m_verifier.setShared(true); 56 // If this assert fires, it either indicates a thread safety issue or 57 // that the verification needs to change. See ThreadRestrictionVerifier for 58 // the different modes. 59 ASSERT(m_verifier.isSafeToUse()); 60 ASSERT(!m_deletionHasBegun); 61 ASSERT(!m_adoptionIsRequired); 62#endif 63 ++m_refCount; 64 } 65 66 bool hasOneRef() const 67 { 68#if CHECK_REF_COUNTED_LIFECYCLE 69 ASSERT(m_verifier.isSafeToUse()); 70 ASSERT(!m_deletionHasBegun); 71#endif 72 return m_refCount == 1; 73 } 74 75 int refCount() const 76 { 77#if CHECK_REF_COUNTED_LIFECYCLE 78 ASSERT(m_verifier.isSafeToUse()); 79#endif 80 return m_refCount; 81 } 82 83 void relaxAdoptionRequirement() 84 { 85#if CHECK_REF_COUNTED_LIFECYCLE 86 ASSERT(!m_deletionHasBegun); 87 ASSERT(m_adoptionIsRequired); 88 m_adoptionIsRequired = false; 89#endif 90 } 91 92protected: 93 RefCountedBase() 94 : m_refCount(1) 95#if CHECK_REF_COUNTED_LIFECYCLE 96 , m_deletionHasBegun(false) 97 , m_adoptionIsRequired(true) 98#endif 99 { 100 } 101 102 ~RefCountedBase() 103 { 104#if CHECK_REF_COUNTED_LIFECYCLE 105 ASSERT(m_deletionHasBegun); 106 ASSERT(!m_adoptionIsRequired); 107#endif 108 } 109 110 // Returns whether the pointer should be freed or not. 111 bool derefBase() 112 { 113#if CHECK_REF_COUNTED_LIFECYCLE 114 ASSERT(m_verifier.isSafeToUse()); 115 ASSERT(!m_deletionHasBegun); 116 ASSERT(!m_adoptionIsRequired); 117#endif 118 119 ASSERT(m_refCount > 0); 120 if (m_refCount == 1) { 121#if CHECK_REF_COUNTED_LIFECYCLE 122 m_deletionHasBegun = true; 123#endif 124 return true; 125 } 126 127 --m_refCount; 128#if CHECK_REF_COUNTED_LIFECYCLE 129 // Stop thread verification when the ref goes to 1 because it 130 // is safe to be passed to another thread at this point. 131 if (m_refCount == 1) 132 m_verifier.setShared(false); 133#endif 134 return false; 135 } 136 137#if CHECK_REF_COUNTED_LIFECYCLE 138 bool deletionHasBegun() const 139 { 140 return m_deletionHasBegun; 141 } 142#endif 143 144private: 145 146#if CHECK_REF_COUNTED_LIFECYCLE 147 friend void adopted(RefCountedBase*); 148#endif 149 150 int m_refCount; 151#if CHECK_REF_COUNTED_LIFECYCLE 152 bool m_deletionHasBegun; 153 bool m_adoptionIsRequired; 154 ThreadRestrictionVerifier m_verifier; 155#endif 156}; 157 158#if CHECK_REF_COUNTED_LIFECYCLE 159inline void adopted(RefCountedBase* object) 160{ 161 if (!object) 162 return; 163 ASSERT(!object->m_deletionHasBegun); 164 object->m_adoptionIsRequired = false; 165} 166#endif 167 168template<typename T> class RefCounted : public RefCountedBase { 169 WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED; 170public: 171 void deref() 172 { 173 if (derefBase()) 174 delete static_cast<T*>(this); 175 } 176 177protected: 178 RefCounted() { } 179 ~RefCounted() 180 { 181 } 182}; 183 184template<typename T> class RefCountedCustomAllocated : public RefCountedBase { 185 WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated); 186 187public: 188 void deref() 189 { 190 if (derefBase()) 191 delete static_cast<T*>(this); 192 } 193 194protected: 195 ~RefCountedCustomAllocated() 196 { 197 } 198}; 199 200} // namespace WTF 201 202using WTF::RefCounted; 203using WTF::RefCountedCustomAllocated; 204 205#endif // RefCounted_h 206