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
37 namespace 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).
42 class WTF_EXPORT RefCountedBase {
43 public:
ref()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
hasOneRef()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
refCount()74 int refCount() const
75 {
76 #if CHECK_REF_COUNTED_LIFECYCLE
77 ASSERT(m_verifier.isSafeToUse());
78 #endif
79 return m_refCount;
80 }
81
relaxAdoptionRequirement()82 void relaxAdoptionRequirement()
83 {
84 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
85 #if CHECK_REF_COUNTED_LIFECYCLE
86 ASSERT(m_adoptionIsRequired);
87 m_adoptionIsRequired = false;
88 #endif
89 }
90
91 protected:
RefCountedBase()92 RefCountedBase()
93 : m_refCount(1)
94 #if SECURITY_ASSERT_ENABLED
95 , m_deletionHasBegun(false)
96 #endif
97 #if CHECK_REF_COUNTED_LIFECYCLE
98 , m_adoptionIsRequired(true)
99 #endif
100 {
101 }
102
~RefCountedBase()103 ~RefCountedBase()
104 {
105 ASSERT_WITH_SECURITY_IMPLICATION(m_deletionHasBegun);
106 #if CHECK_REF_COUNTED_LIFECYCLE
107 ASSERT(!m_adoptionIsRequired);
108 #endif
109 }
110
111 // Returns whether the pointer should be freed or not.
derefBase()112 bool derefBase()
113 {
114 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
115 #if CHECK_REF_COUNTED_LIFECYCLE
116 ASSERT(m_verifier.isSafeToUse());
117 ASSERT(!m_adoptionIsRequired);
118 #endif
119
120 ASSERT(m_refCount > 0);
121 if (m_refCount == 1) {
122 #if SECURITY_ASSERT_ENABLED
123 m_deletionHasBegun = true;
124 #endif
125 return true;
126 }
127
128 --m_refCount;
129 #if CHECK_REF_COUNTED_LIFECYCLE
130 // Stop thread verification when the ref goes to 1 because it
131 // is safe to be passed to another thread at this point.
132 if (m_refCount == 1)
133 m_verifier.setShared(false);
134 #endif
135 return false;
136 }
137
138 #if CHECK_REF_COUNTED_LIFECYCLE
deletionHasBegun()139 bool deletionHasBegun() const
140 {
141 return m_deletionHasBegun;
142 }
143 #endif
144
145 private:
146
147 #if CHECK_REF_COUNTED_LIFECYCLE || SECURITY_ASSERT_ENABLED
148 friend void adopted(RefCountedBase*);
149 #endif
150
151 int m_refCount;
152 #if SECURITY_ASSERT_ENABLED
153 bool m_deletionHasBegun;
154 #endif
155 #if CHECK_REF_COUNTED_LIFECYCLE
156 bool m_adoptionIsRequired;
157 ThreadRestrictionVerifier m_verifier;
158 #endif
159 };
160
161 #if CHECK_REF_COUNTED_LIFECYCLE || SECURITY_ASSERT_ENABLED
adopted(RefCountedBase * object)162 inline void adopted(RefCountedBase* object)
163 {
164 if (!object)
165 return;
166 ASSERT_WITH_SECURITY_IMPLICATION(!object->m_deletionHasBegun);
167 #if CHECK_REF_COUNTED_LIFECYCLE
168 object->m_adoptionIsRequired = false;
169 #endif
170 }
171 #endif
172
173 template<typename T> class RefCounted : public RefCountedBase {
174 WTF_MAKE_NONCOPYABLE(RefCounted);
175 WTF_MAKE_FAST_ALLOCATED;
176
177 public:
deref()178 void deref()
179 {
180 if (derefBase())
181 delete static_cast<T*>(this);
182 }
183
184 protected:
185 #ifdef ENABLE_INSTANCE_COUNTER
RefCounted()186 RefCounted()
187 {
188 incrementInstanceCount<T>(static_cast<T*>(this));
189 }
190
~RefCounted()191 ~RefCounted()
192 {
193 decrementInstanceCount<T>(static_cast<T*>(this));
194 }
195 #else
196 RefCounted()
197 {
198 }
199 #endif
200 };
201
202 } // namespace WTF
203
204 using WTF::RefCounted;
205
206 #endif // RefCounted_h
207