]> git.saurik.com Git - apple/javascriptcore.git/blob - wtf/CrossThreadRefCounted.h
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / wtf / CrossThreadRefCounted.h
1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * Copyright (C) 2010 Apple Inc. All rights reserved.
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
35 #include "PassRefPtr.h"
36 #include "RefCounted.h"
37 #include "Threading.h"
38
39 #include <wtf/iphone/WebCoreThread.h>
40
41 namespace WTF {
42
43 // Used to allowing sharing data across classes and threads (like ThreadSafeRefCounted).
44 //
45 // Why not just use ThreadSafeRefCounted?
46 // ThreadSafeRefCounted can have a significant perf impact when used in low level classes
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>
56 class CrossThreadRefCounted {
57 WTF_MAKE_NONCOPYABLE(CrossThreadRefCounted);
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
76 private:
77 CrossThreadRefCounted(T* data, ThreadSafeRefCountedBase* threadedCounter)
78 : m_threadSafeRefCounter(threadedCounter)
79 , m_data(data)
80 #ifndef NDEBUG
81 , m_threadId(0)
82 #endif
83 {
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();
87 }
88
89 ~CrossThreadRefCounted()
90 {
91 if (!m_threadSafeRefCounter)
92 delete m_data;
93 }
94
95 void threadSafeDeref();
96
97 #ifndef NDEBUG
98 bool isOwnedByCurrentThread() const {
99 return !m_threadId || m_threadId == currentThread() || ((isMainThread() || pthread_main_np()) && WebCoreWebThreadIsLockedOrDisabled());
100 }
101 #endif
102
103 RefCountedBase m_refCounter;
104 ThreadSafeRefCountedBase* m_threadSafeRefCounter;
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 {
114 ASSERT(isOwnedByCurrentThread());
115
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 {
131 ASSERT(isOwnedByCurrentThread());
132
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 {
159 ASSERT(isOwnedByCurrentThread());
160
161 if (m_threadSafeRefCounter)
162 m_threadSafeRefCounter->ref();
163 else
164 m_threadSafeRefCounter = new ThreadSafeRefCountedBase(2);
165
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