2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * Copyright (C) 2010 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #ifndef CrossThreadRefCounted_h
33 #define CrossThreadRefCounted_h
35 #include "PassRefPtr.h"
36 #include "RefCounted.h"
37 #include "Threading.h"
39 #include <wtf/iphone/WebCoreThread.h>
43 // Used to allowing sharing data across classes and threads (like ThreadSafeRefCounted).
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.
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.
56 class CrossThreadRefCounted
{
57 WTF_MAKE_NONCOPYABLE(CrossThreadRefCounted
);
59 static PassRefPtr
<CrossThreadRefCounted
<T
> > create(T
* data
)
61 return adoptRef(new CrossThreadRefCounted
<T
>(data
, 0));
64 // Used to make an instance that can be used on another thread.
65 PassRefPtr
<CrossThreadRefCounted
<T
> > crossThreadCopy();
73 return !m_refCounter
.hasOneRef() || (m_threadSafeRefCounter
&& !m_threadSafeRefCounter
->hasOneRef());
77 CrossThreadRefCounted(T
* data
, ThreadSafeRefCountedBase
* threadedCounter
)
78 : m_threadSafeRefCounter(threadedCounter
)
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();
89 ~CrossThreadRefCounted()
91 if (!m_threadSafeRefCounter
)
95 void threadSafeDeref();
98 bool isOwnedByCurrentThread() const {
99 return !m_threadId
|| m_threadId
== currentThread() || ((isMainThread() || pthread_main_np()) && WebCoreWebThreadIsLockedOrDisabled());
103 RefCountedBase m_refCounter
;
104 ThreadSafeRefCountedBase
* m_threadSafeRefCounter
;
107 ThreadIdentifier m_threadId
;
112 void CrossThreadRefCounted
<T
>::ref()
114 ASSERT(isOwnedByCurrentThread());
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
123 if (!m_threadId
&& m_refCounter
.refCount() == 2)
124 m_threadId
= currentThread();
129 void CrossThreadRefCounted
<T
>::deref()
131 ASSERT(isOwnedByCurrentThread());
133 if (m_refCounter
.derefBase()) {
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)
147 T
* CrossThreadRefCounted
<T
>::release()
157 PassRefPtr
<CrossThreadRefCounted
<T
> > CrossThreadRefCounted
<T
>::crossThreadCopy()
159 ASSERT(isOwnedByCurrentThread());
161 if (m_threadSafeRefCounter
)
162 m_threadSafeRefCounter
->ref();
164 m_threadSafeRefCounter
= new ThreadSafeRefCountedBase(2);
166 return adoptRef(new CrossThreadRefCounted
<T
>(m_data
, m_threadSafeRefCounter
));
171 void CrossThreadRefCounted
<T
>::threadSafeDeref()
173 if (m_threadSafeRefCounter
&& m_threadSafeRefCounter
->derefBase()) {
174 delete m_threadSafeRefCounter
;
175 m_threadSafeRefCounter
= 0;
180 using WTF::CrossThreadRefCounted
;
182 #endif // CrossThreadRefCounted_h