]>
Commit | Line | Data |
---|---|---|
ba379fdc A |
1 | /* |
2 | * Copyright (C) 2009 Google Inc. All rights reserved. | |
14957cd0 | 3 | * Copyright (C) 2010 Apple Inc. All rights reserved. |
ba379fdc A |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions are | |
7 | * met: | |
8 | * | |
9 | * * Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * * Redistributions in binary form must reproduce the above | |
12 | * copyright notice, this list of conditions and the following disclaimer | |
13 | * in the documentation and/or other materials provided with the | |
14 | * distribution. | |
15 | * * Neither the name of Google Inc. nor the names of its | |
16 | * contributors may be used to endorse or promote products derived from | |
17 | * this software without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | |
31 | ||
32 | #ifndef CrossThreadRefCounted_h | |
33 | #define CrossThreadRefCounted_h | |
34 | ||
14957cd0 A |
35 | #include "PassRefPtr.h" |
36 | #include "RefCounted.h" | |
37 | #include "Threading.h" | |
ba379fdc | 38 | |
f9bf01c6 A |
39 | #include <wtf/iphone/WebCoreThread.h> |
40 | ||
ba379fdc A |
41 | namespace WTF { |
42 | ||
14957cd0 | 43 | // Used to allowing sharing data across classes and threads (like ThreadSafeRefCounted). |
ba379fdc | 44 | // |
14957cd0 A |
45 | // Why not just use ThreadSafeRefCounted? |
46 | // ThreadSafeRefCounted can have a significant perf impact when used in low level classes | |
ba379fdc A |
47 | // (like UString) that get ref/deref'ed a lot. This class has the benefit of doing fast ref |
48 | // counts like RefPtr whenever possible, but it has the downside that you need to copy it | |
49 | // to use it on another thread. | |
50 | // | |
51 | // Is this class threadsafe? | |
52 | // While each instance of the class is not threadsafe, the copied instance is threadsafe | |
53 | // with respect to the original and any other copies. The underlying m_data is jointly | |
54 | // owned by the original instance and all copies. | |
55 | template<class T> | |
14957cd0 A |
56 | class CrossThreadRefCounted { |
57 | WTF_MAKE_NONCOPYABLE(CrossThreadRefCounted); | |
ba379fdc A |
58 | public: |
59 | static PassRefPtr<CrossThreadRefCounted<T> > create(T* data) | |
60 | { | |
61 | return adoptRef(new CrossThreadRefCounted<T>(data, 0)); | |
62 | } | |
63 | ||
64 | // Used to make an instance that can be used on another thread. | |
65 | PassRefPtr<CrossThreadRefCounted<T> > crossThreadCopy(); | |
66 | ||
67 | void ref(); | |
68 | void deref(); | |
69 | T* release(); | |
70 | ||
71 | bool isShared() const | |
72 | { | |
73 | return !m_refCounter.hasOneRef() || (m_threadSafeRefCounter && !m_threadSafeRefCounter->hasOneRef()); | |
74 | } | |
75 | ||
ba379fdc | 76 | private: |
14957cd0 | 77 | CrossThreadRefCounted(T* data, ThreadSafeRefCountedBase* threadedCounter) |
ba379fdc A |
78 | : m_threadSafeRefCounter(threadedCounter) |
79 | , m_data(data) | |
80 | #ifndef NDEBUG | |
81 | , m_threadId(0) | |
82 | #endif | |
83 | { | |
14957cd0 A |
84 | // We use RefCountedBase in an unusual way here, so get rid of the requirement |
85 | // that adoptRef be called on it. | |
86 | m_refCounter.relaxAdoptionRequirement(); | |
ba379fdc A |
87 | } |
88 | ||
89 | ~CrossThreadRefCounted() | |
90 | { | |
91 | if (!m_threadSafeRefCounter) | |
92 | delete m_data; | |
93 | } | |
94 | ||
95 | void threadSafeDeref(); | |
96 | ||
f9bf01c6 A |
97 | #ifndef NDEBUG |
98 | bool isOwnedByCurrentThread() const { | |
99 | return !m_threadId || m_threadId == currentThread() || ((isMainThread() || pthread_main_np()) && WebCoreWebThreadIsLockedOrDisabled()); | |
100 | } | |
101 | #endif | |
102 | ||
ba379fdc | 103 | RefCountedBase m_refCounter; |
14957cd0 | 104 | ThreadSafeRefCountedBase* m_threadSafeRefCounter; |
ba379fdc A |
105 | T* m_data; |
106 | #ifndef NDEBUG | |
107 | ThreadIdentifier m_threadId; | |
108 | #endif | |
109 | }; | |
110 | ||
111 | template<class T> | |
112 | void CrossThreadRefCounted<T>::ref() | |
113 | { | |
f9bf01c6 A |
114 | ASSERT(isOwnedByCurrentThread()); |
115 | ||
ba379fdc A |
116 | m_refCounter.ref(); |
117 | #ifndef NDEBUG | |
118 | // Store the threadId as soon as the ref count gets to 2. | |
119 | // The class gets created with a ref count of 1 and then passed | |
120 | // to another thread where to ref count get increased. This | |
121 | // is a heuristic but it seems to always work and has helped | |
122 | // find some bugs. | |
123 | if (!m_threadId && m_refCounter.refCount() == 2) | |
124 | m_threadId = currentThread(); | |
125 | #endif | |
126 | } | |
127 | ||
128 | template<class T> | |
129 | void CrossThreadRefCounted<T>::deref() | |
130 | { | |
f9bf01c6 A |
131 | ASSERT(isOwnedByCurrentThread()); |
132 | ||
ba379fdc A |
133 | if (m_refCounter.derefBase()) { |
134 | threadSafeDeref(); | |
135 | delete this; | |
136 | } else { | |
137 | #ifndef NDEBUG | |
138 | // Clear the threadId when the ref goes to 1 because it | |
139 | // is safe to be passed to another thread at this point. | |
140 | if (m_threadId && m_refCounter.refCount() == 1) | |
141 | m_threadId = 0; | |
142 | #endif | |
143 | } | |
144 | } | |
145 | ||
146 | template<class T> | |
147 | T* CrossThreadRefCounted<T>::release() | |
148 | { | |
149 | ASSERT(!isShared()); | |
150 | ||
151 | T* data = m_data; | |
152 | m_data = 0; | |
153 | return data; | |
154 | } | |
155 | ||
156 | template<class T> | |
157 | PassRefPtr<CrossThreadRefCounted<T> > CrossThreadRefCounted<T>::crossThreadCopy() | |
158 | { | |
f9bf01c6 A |
159 | ASSERT(isOwnedByCurrentThread()); |
160 | ||
ba379fdc A |
161 | if (m_threadSafeRefCounter) |
162 | m_threadSafeRefCounter->ref(); | |
163 | else | |
14957cd0 | 164 | m_threadSafeRefCounter = new ThreadSafeRefCountedBase(2); |
f9bf01c6 | 165 | |
ba379fdc A |
166 | return adoptRef(new CrossThreadRefCounted<T>(m_data, m_threadSafeRefCounter)); |
167 | } | |
168 | ||
169 | ||
170 | template<class T> | |
171 | void CrossThreadRefCounted<T>::threadSafeDeref() | |
172 | { | |
173 | if (m_threadSafeRefCounter && m_threadSafeRefCounter->derefBase()) { | |
174 | delete m_threadSafeRefCounter; | |
175 | m_threadSafeRefCounter = 0; | |
176 | } | |
177 | } | |
178 | } // namespace WTF | |
179 | ||
180 | using WTF::CrossThreadRefCounted; | |
181 | ||
182 | #endif // CrossThreadRefCounted_h |