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/FastAllocBase.h" 25#include "wtf/InstanceCounter.h" 26#include "wtf/Noncopyable.h" 27#include "wtf/WTFExport.h" 28 29#ifdef NDEBUG 30#define CHECK_REF_COUNTED_LIFECYCLE 0 31#else 32#define CHECK_REF_COUNTED_LIFECYCLE 1 33#include "wtf/Assertions.h" 34#include "wtf/ThreadRestrictionVerifier.h" 35#endif 36 37namespace WTF { 38 39// This base class holds the non-template methods and attributes. 40// The RefCounted class inherits from it reducing the template bloat 41// generated by the compiler (technique called template hoisting). 42class WTF_EXPORT RefCountedBase { 43public: 44 void ref() 45 { 46#if CHECK_REF_COUNTED_LIFECYCLE 47 // Start thread verification as soon as the ref count gets to 2. This 48 // heuristic reflects the fact that items are often created on one thread 49 // and then given to another thread to be used. 50 // FIXME: Make this restriction tigher. Especially as we move to more 51 // common methods for sharing items across threads like CrossThreadCopier.h 52 // We should be able to add a "detachFromThread" method to make this explicit. 53 if (m_refCount == 1) 54 m_verifier.setShared(true); 55 // If this assert fires, it either indicates a thread safety issue or 56 // that the verification needs to change. See ThreadRestrictionVerifier for 57 // the different modes. 58 ASSERT(m_verifier.isSafeToUse()); 59 ASSERT(!m_adoptionIsRequired); 60#endif 61 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun); 62 ++m_refCount; 63 } 64 65 bool hasOneRef() const 66 { 67 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun); 68#if CHECK_REF_COUNTED_LIFECYCLE 69 ASSERT(m_verifier.isSafeToUse()); 70#endif 71 return m_refCount == 1; 72 } 73 74 int refCount() const 75 { 76#if CHECK_REF_COUNTED_LIFECYCLE 77 ASSERT(m_verifier.isSafeToUse()); 78#endif 79 return m_refCount; 80 } 81 82protected: 83 RefCountedBase() 84 : m_refCount(1) 85#if SECURITY_ASSERT_ENABLED 86 , m_deletionHasBegun(false) 87#endif 88#if CHECK_REF_COUNTED_LIFECYCLE 89 , m_adoptionIsRequired(true) 90#endif 91 { 92 } 93 94 ~RefCountedBase() 95 { 96 ASSERT_WITH_SECURITY_IMPLICATION(m_deletionHasBegun); 97#if CHECK_REF_COUNTED_LIFECYCLE 98 ASSERT(!m_adoptionIsRequired); 99#endif 100 } 101 102 // Returns whether the pointer should be freed or not. 103 bool derefBase() 104 { 105 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun); 106#if CHECK_REF_COUNTED_LIFECYCLE 107 ASSERT(m_verifier.isSafeToUse()); 108 ASSERT(!m_adoptionIsRequired); 109#endif 110 111 ASSERT(m_refCount > 0); 112 --m_refCount; 113 if (!m_refCount) { 114#if SECURITY_ASSERT_ENABLED 115 m_deletionHasBegun = true; 116#endif 117 return true; 118 } 119 120#if CHECK_REF_COUNTED_LIFECYCLE 121 // Stop thread verification when the ref goes to 1 because it 122 // is safe to be passed to another thread at this point. 123 if (m_refCount == 1) 124 m_verifier.setShared(false); 125#endif 126 return false; 127 } 128 129#if CHECK_REF_COUNTED_LIFECYCLE 130 bool deletionHasBegun() const 131 { 132 return m_deletionHasBegun; 133 } 134#endif 135 136private: 137 138#if CHECK_REF_COUNTED_LIFECYCLE || SECURITY_ASSERT_ENABLED 139 friend void adopted(RefCountedBase*); 140#endif 141 142 int m_refCount; 143#if SECURITY_ASSERT_ENABLED 144 bool m_deletionHasBegun; 145#endif 146#if CHECK_REF_COUNTED_LIFECYCLE 147 bool m_adoptionIsRequired; 148 ThreadRestrictionVerifier m_verifier; 149#endif 150}; 151 152#if CHECK_REF_COUNTED_LIFECYCLE || SECURITY_ASSERT_ENABLED 153inline void adopted(RefCountedBase* object) 154{ 155 if (!object) 156 return; 157 ASSERT_WITH_SECURITY_IMPLICATION(!object->m_deletionHasBegun); 158#if CHECK_REF_COUNTED_LIFECYCLE 159 object->m_adoptionIsRequired = false; 160#endif 161} 162#endif 163 164template<typename T> class RefCounted : public RefCountedBase { 165 WTF_MAKE_NONCOPYABLE(RefCounted); 166 WTF_MAKE_FAST_ALLOCATED; 167 168public: 169 void deref() 170 { 171 if (derefBase()) 172 delete static_cast<T*>(this); 173 } 174 175protected: 176#ifdef ENABLE_INSTANCE_COUNTER 177 RefCounted() 178 { 179 incrementInstanceCount<T>(static_cast<T*>(this)); 180 } 181 182 ~RefCounted() 183 { 184 decrementInstanceCount<T>(static_cast<T*>(this)); 185 } 186#else 187 RefCounted() 188 { 189 } 190#endif 191}; 192 193} // namespace WTF 194 195using WTF::RefCounted; 196 197#endif // RefCounted_h 198