Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
| 6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
| 7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
| 8 * | 8 * |
| 9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 #include <wtf/Noncopyable.h> | 26 #include <wtf/Noncopyable.h> |
| 27 #include <wtf/OwnPtr.h> | 27 #include <wtf/OwnPtr.h> |
| 28 #include <wtf/ThreadRestrictionVerifier.h> | 28 #include <wtf/ThreadRestrictionVerifier.h> |
| 29 #include <wtf/UnusedParam.h> | 29 #include <wtf/UnusedParam.h> |
| 30 | 30 |
| 31 namespace WTF { | 31 namespace WTF { |
| 32 | 32 |
| 33 #ifdef NDEBUG | 33 #ifdef NDEBUG |
| 34 #define CHECK_REF_COUNTED_LIFECYCLE 0 | 34 #define CHECK_REF_COUNTED_LIFECYCLE 0 |
| 35 #else | 35 #else |
| 36 #define CHECK_REF_COUNTED_LIFECYCLE 1 | 36 // FIXME(oilpan): Enable this check once we replace all |
| 37 // RefCountedHeapAllocated with HeapAllocated. | |
| 38 // We have to disable the check for RefCountedHeapAllocated | |
| 39 // since we have to allow the following situation in RefCountedHeapAllocated. | |
| 40 // (1) A reference count becomes 0, but Handles keep references to the object. | |
| 41 // (2) The Handle is assigned to a RefPtr. The reference count becomes 1. | |
| 42 #define CHECK_REF_COUNTED_LIFECYCLE 0 | |
| 37 #endif | 43 #endif |
| 38 | 44 |
| 39 // This base class holds the non-template methods and attributes. | 45 // This base class holds the non-template methods and attributes. |
| 40 // The RefCounted class inherits from it reducing the template bloat | 46 // The RefCounted class inherits from it reducing the template bloat |
| 41 // generated by the compiler (technique called template hoisting). | 47 // generated by the compiler (technique called template hoisting). |
| 42 class RefCountedBase { | 48 class RefCountedBase { |
| 43 public: | 49 public: |
| 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 threa d | |
| 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 CrossThreadCopie r.h | |
| 52 // We should be able to add a "detachFromThread" method to make this exp licit. | |
| 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_deletionHasBegun); | |
| 60 ASSERT(!m_adoptionIsRequired); | |
| 61 #endif | |
| 62 ++m_refCount; | |
| 63 } | |
| 64 | |
| 65 bool hasOneRef() const | 50 bool hasOneRef() const |
| 66 { | 51 { |
| 67 #if CHECK_REF_COUNTED_LIFECYCLE | 52 #if CHECK_REF_COUNTED_LIFECYCLE |
| 68 ASSERT(m_verifier.isSafeToUse()); | 53 ASSERT(m_verifier.isSafeToUse()); |
| 69 ASSERT(!m_deletionHasBegun); | 54 ASSERT(!m_deletionHasBegun); |
| 70 #endif | 55 #endif |
| 71 return m_refCount == 1; | 56 return m_refCount == 1; |
| 72 } | 57 } |
| 73 | 58 |
| 74 int refCount() const | 59 int refCount() const |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 128 } | 113 } |
| 129 | 114 |
| 130 ~RefCountedBase() | 115 ~RefCountedBase() |
| 131 { | 116 { |
| 132 #if CHECK_REF_COUNTED_LIFECYCLE | 117 #if CHECK_REF_COUNTED_LIFECYCLE |
| 133 ASSERT(m_deletionHasBegun); | 118 ASSERT(m_deletionHasBegun); |
| 134 ASSERT(!m_adoptionIsRequired); | 119 ASSERT(!m_adoptionIsRequired); |
| 135 #endif | 120 #endif |
| 136 } | 121 } |
| 137 | 122 |
| 123 void refBase() | |
| 124 { | |
| 125 #if CHECK_REF_COUNTED_LIFECYCLE | |
| 126 // Start thread verification as soon as the ref count gets to 2. This | |
| 127 // heuristic reflects the fact that items are often created on one threa d | |
| 128 // and then given to another thread to be used. | |
| 129 // FIXME: Make this restriction tigher. Especially as we move to more | |
| 130 // common methods for sharing items across threads like CrossThreadCopie r.h | |
| 131 // We should be able to add a "detachFromThread" method to make this exp licit. | |
| 132 if (m_refCount == 1) | |
| 133 m_verifier.setShared(true); | |
| 134 // If this assert fires, it either indicates a thread safety issue or | |
| 135 // that the verification needs to change. See ThreadRestrictionVerifier for | |
| 136 // the different modes. | |
| 137 ASSERT(m_verifier.isSafeToUse()); | |
| 138 ASSERT(!m_deletionHasBegun); | |
| 139 ASSERT(!m_adoptionIsRequired); | |
| 140 #endif | |
| 141 ++m_refCount; | |
| 142 } | |
| 143 | |
| 138 // Returns whether the pointer should be freed or not. | 144 // Returns whether the pointer should be freed or not. |
| 139 bool derefBase() | 145 bool derefBase() |
| 140 { | 146 { |
| 141 #if CHECK_REF_COUNTED_LIFECYCLE | 147 #if CHECK_REF_COUNTED_LIFECYCLE |
| 142 ASSERT(m_verifier.isSafeToUse()); | 148 ASSERT(m_verifier.isSafeToUse()); |
| 143 ASSERT(!m_deletionHasBegun); | 149 ASSERT(!m_deletionHasBegun); |
| 144 ASSERT(!m_adoptionIsRequired); | 150 ASSERT(!m_adoptionIsRequired); |
| 145 #endif | 151 #endif |
| 146 | 152 |
| 147 ASSERT(m_refCount > 0); | 153 ASSERT(m_refCount > 0); |
| 148 if (m_refCount == 1) { | 154 if (m_refCount == 1) { |
| 149 #if CHECK_REF_COUNTED_LIFECYCLE | 155 #if CHECK_REF_COUNTED_LIFECYCLE |
| 150 m_deletionHasBegun = true; | 156 m_deletionHasBegun = true; |
| 151 #endif | 157 #endif |
| 158 --m_refCount; | |
|
haraken
2013/05/29 14:53:45
This is critical :)
Mads Ager (chromium)
2013/05/29 16:46:38
Yeah, I see, otherwise the ref will actually never
| |
| 152 return true; | 159 return true; |
| 153 } | 160 } |
| 154 | 161 |
| 155 --m_refCount; | 162 --m_refCount; |
| 156 #if CHECK_REF_COUNTED_LIFECYCLE | 163 #if CHECK_REF_COUNTED_LIFECYCLE |
| 157 // Stop thread verification when the ref goes to 1 because it | 164 // Stop thread verification when the ref goes to 1 because it |
| 158 // is safe to be passed to another thread at this point. | 165 // is safe to be passed to another thread at this point. |
| 159 if (m_refCount == 1) | 166 if (m_refCount == 1) |
| 160 m_verifier.setShared(false); | 167 m_verifier.setShared(false); |
| 161 #endif | 168 #endif |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 189 if (!object) | 196 if (!object) |
| 190 return; | 197 return; |
| 191 ASSERT(!object->m_deletionHasBegun); | 198 ASSERT(!object->m_deletionHasBegun); |
| 192 object->m_adoptionIsRequired = false; | 199 object->m_adoptionIsRequired = false; |
| 193 } | 200 } |
| 194 #endif | 201 #endif |
| 195 | 202 |
| 196 template<typename T> class RefCounted : public RefCountedBase { | 203 template<typename T> class RefCounted : public RefCountedBase { |
| 197 WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED; | 204 WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED; |
| 198 public: | 205 public: |
| 206 void ref() | |
| 207 { | |
| 208 refBase(); | |
| 209 } | |
| 210 | |
| 199 void deref() | 211 void deref() |
| 200 { | 212 { |
| 201 if (derefBase()) | 213 if (derefBase()) |
| 202 delete static_cast<T*>(this); | 214 delete static_cast<T*>(this); |
| 203 } | 215 } |
| 204 | 216 |
| 205 protected: | 217 protected: |
| 206 RefCounted() { } | 218 RefCounted() { } |
| 207 ~RefCounted() | 219 ~RefCounted() |
| 208 { | 220 { |
| 209 } | 221 } |
| 210 }; | 222 }; |
| 211 | 223 |
| 212 template<typename T> class RefCountedCustomAllocated : public RefCountedBase { | 224 template<typename T> class RefCountedCustomAllocated : public RefCountedBase { |
| 213 WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated); | 225 WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated); |
| 214 | 226 |
| 215 public: | 227 public: |
| 228 void ref() | |
| 229 { | |
| 230 refBase(); | |
| 231 } | |
| 232 | |
| 216 void deref() | 233 void deref() |
| 217 { | 234 { |
| 218 if (derefBase()) | 235 if (derefBase()) |
| 219 delete static_cast<T*>(this); | 236 delete static_cast<T*>(this); |
| 220 } | 237 } |
| 221 | 238 |
| 222 protected: | 239 protected: |
| 223 ~RefCountedCustomAllocated() | 240 ~RefCountedCustomAllocated() |
| 224 { | 241 { |
| 225 } | 242 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 244 inline void RefCountedBase::setDispatchQueueForVerifier(dispatch_queue_t) { } | 261 inline void RefCountedBase::setDispatchQueueForVerifier(dispatch_queue_t) { } |
| 245 #endif | 262 #endif |
| 246 #endif // HAVE(DISPATCH_H) | 263 #endif // HAVE(DISPATCH_H) |
| 247 | 264 |
| 248 } // namespace WTF | 265 } // namespace WTF |
| 249 | 266 |
| 250 using WTF::RefCounted; | 267 using WTF::RefCounted; |
| 251 using WTF::RefCountedCustomAllocated; | 268 using WTF::RefCountedCustomAllocated; |
| 252 | 269 |
| 253 #endif // RefCounted_h | 270 #endif // RefCounted_h |
| OLD | NEW |