Home | History | Annotate | Download | only in wtf
      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:
     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 
     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:
     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 
    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.
    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
    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
    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:
    178     void deref()
    179     {
    180         if (derefBase())
    181             delete static_cast<T*>(this);
    182     }
    183 
    184 protected:
    185 #ifdef ENABLE_INSTANCE_COUNTER
    186     RefCounted()
    187     {
    188         incrementInstanceCount<T>(static_cast<T*>(this));
    189     }
    190 
    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