• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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