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/Noncopyable.h"
27#include "wtf/OwnPtr.h"
28#include "wtf/ThreadRestrictionVerifier.h"
29#include "wtf/UnusedParam.h"
30#include "wtf/WTFExport.h"
31
32namespace WTF {
33
34#ifdef NDEBUG
35#define CHECK_REF_COUNTED_LIFECYCLE 0
36#else
37#define CHECK_REF_COUNTED_LIFECYCLE 1
38#endif
39
40// This base class holds the non-template methods and attributes.
41// The RefCounted class inherits from it reducing the template bloat
42// generated by the compiler (technique called template hoisting).
43class WTF_EXPORT RefCountedBase {
44public:
45    void ref()
46    {
47#if CHECK_REF_COUNTED_LIFECYCLE
48        // Start thread verification as soon as the ref count gets to 2. This
49        // heuristic reflects the fact that items are often created on one thread
50        // and then given to another thread to be used.
51        // FIXME: Make this restriction tigher. Especially as we move to more
52        // common methods for sharing items across threads like CrossThreadCopier.h
53        // We should be able to add a "detachFromThread" method to make this explicit.
54        if (m_refCount == 1)
55            m_verifier.setShared(true);
56        // If this assert fires, it either indicates a thread safety issue or
57        // that the verification needs to change. See ThreadRestrictionVerifier for
58        // the different modes.
59        ASSERT(m_verifier.isSafeToUse());
60        ASSERT(!m_deletionHasBegun);
61        ASSERT(!m_adoptionIsRequired);
62#endif
63        ++m_refCount;
64    }
65
66    bool hasOneRef() const
67    {
68#if CHECK_REF_COUNTED_LIFECYCLE
69        ASSERT(m_verifier.isSafeToUse());
70        ASSERT(!m_deletionHasBegun);
71#endif
72        return m_refCount == 1;
73    }
74
75    int refCount() const
76    {
77#if CHECK_REF_COUNTED_LIFECYCLE
78        ASSERT(m_verifier.isSafeToUse());
79#endif
80        return m_refCount;
81    }
82
83    void relaxAdoptionRequirement()
84    {
85#if CHECK_REF_COUNTED_LIFECYCLE
86        ASSERT(!m_deletionHasBegun);
87        ASSERT(m_adoptionIsRequired);
88        m_adoptionIsRequired = false;
89#endif
90    }
91
92protected:
93    RefCountedBase()
94        : m_refCount(1)
95#if CHECK_REF_COUNTED_LIFECYCLE
96        , m_deletionHasBegun(false)
97        , m_adoptionIsRequired(true)
98#endif
99    {
100    }
101
102    ~RefCountedBase()
103    {
104#if CHECK_REF_COUNTED_LIFECYCLE
105        ASSERT(m_deletionHasBegun);
106        ASSERT(!m_adoptionIsRequired);
107#endif
108    }
109
110    // Returns whether the pointer should be freed or not.
111    bool derefBase()
112    {
113#if CHECK_REF_COUNTED_LIFECYCLE
114        ASSERT(m_verifier.isSafeToUse());
115        ASSERT(!m_deletionHasBegun);
116        ASSERT(!m_adoptionIsRequired);
117#endif
118
119        ASSERT(m_refCount > 0);
120        if (m_refCount == 1) {
121#if CHECK_REF_COUNTED_LIFECYCLE
122            m_deletionHasBegun = true;
123#endif
124            return true;
125        }
126
127        --m_refCount;
128#if CHECK_REF_COUNTED_LIFECYCLE
129        // Stop thread verification when the ref goes to 1 because it
130        // is safe to be passed to another thread at this point.
131        if (m_refCount == 1)
132            m_verifier.setShared(false);
133#endif
134        return false;
135    }
136
137#if CHECK_REF_COUNTED_LIFECYCLE
138    bool deletionHasBegun() const
139    {
140        return m_deletionHasBegun;
141    }
142#endif
143
144private:
145
146#if CHECK_REF_COUNTED_LIFECYCLE
147    friend void adopted(RefCountedBase*);
148#endif
149
150    int m_refCount;
151#if CHECK_REF_COUNTED_LIFECYCLE
152    bool m_deletionHasBegun;
153    bool m_adoptionIsRequired;
154    ThreadRestrictionVerifier m_verifier;
155#endif
156};
157
158#if CHECK_REF_COUNTED_LIFECYCLE
159inline void adopted(RefCountedBase* object)
160{
161    if (!object)
162        return;
163    ASSERT(!object->m_deletionHasBegun);
164    object->m_adoptionIsRequired = false;
165}
166#endif
167
168template<typename T> class RefCounted : public RefCountedBase {
169    WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED;
170public:
171    void deref()
172    {
173        if (derefBase())
174            delete static_cast<T*>(this);
175    }
176
177protected:
178    RefCounted() { }
179    ~RefCounted()
180    {
181    }
182};
183
184template<typename T> class RefCountedCustomAllocated : public RefCountedBase {
185    WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated);
186
187public:
188    void deref()
189    {
190        if (derefBase())
191            delete static_cast<T*>(this);
192    }
193
194protected:
195    ~RefCountedCustomAllocated()
196    {
197    }
198};
199
200} // namespace WTF
201
202using WTF::RefCounted;
203using WTF::RefCountedCustomAllocated;
204
205#endif // RefCounted_h
206