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/Assertions.h"
     25 #include "wtf/FastAllocBase.h"
     26 #include "wtf/InstanceCounter.h"
     27 #include "wtf/Noncopyable.h"
     28 #include "wtf/WTFExport.h"
     29 
     30 #if ENABLE(ASSERT)
     31 #define CHECK_REF_COUNTED_LIFECYCLE 1
     32 #include "wtf/ThreadRestrictionVerifier.h"
     33 #else
     34 #define CHECK_REF_COUNTED_LIFECYCLE 0
     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 protected:
     83     RefCountedBase()
     84         : m_refCount(1)
     85 #if ENABLE(SECURITY_ASSERT)
     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 ENABLE(SECURITY_ASSERT)
    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 
    136 private:
    137 
    138 #if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
    139     friend void adopted(RefCountedBase*);
    140 #endif
    141 
    142     int m_refCount;
    143 #if ENABLE(SECURITY_ASSERT)
    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 || ENABLE(SECURITY_ASSERT)
    153 inline 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 
    164 template<typename T> class RefCounted : public RefCountedBase {
    165     WTF_MAKE_NONCOPYABLE(RefCounted);
    166     WTF_MAKE_FAST_ALLOCATED;
    167 
    168 public:
    169     void deref()
    170     {
    171         if (derefBase())
    172             delete static_cast<T*>(this);
    173     }
    174 
    175 protected:
    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 
    195 using WTF::RefCounted;
    196 
    197 #endif // RefCounted_h
    198