diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/JavaScriptCore/wtf/CrossThreadRefCounted.h | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/JavaScriptCore/wtf/CrossThreadRefCounted.h')
-rw-r--r-- | Source/JavaScriptCore/wtf/CrossThreadRefCounted.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/wtf/CrossThreadRefCounted.h b/Source/JavaScriptCore/wtf/CrossThreadRefCounted.h new file mode 100644 index 0000000..0c0e997 --- /dev/null +++ b/Source/JavaScriptCore/wtf/CrossThreadRefCounted.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CrossThreadRefCounted_h +#define CrossThreadRefCounted_h + +#include "PassRefPtr.h" +#include "RefCounted.h" +#include "Threading.h" + +namespace WTF { + + // Used to allowing sharing data across classes and threads (like ThreadedSafeShared). + // + // Why not just use ThreadSafeShared? + // ThreadSafeShared can have a significant perf impact when used in low level classes + // (like UString) that get ref/deref'ed a lot. This class has the benefit of doing fast ref + // counts like RefPtr whenever possible, but it has the downside that you need to copy it + // to use it on another thread. + // + // Is this class threadsafe? + // While each instance of the class is not threadsafe, the copied instance is threadsafe + // with respect to the original and any other copies. The underlying m_data is jointly + // owned by the original instance and all copies. + template<class T> + class CrossThreadRefCounted : public Noncopyable { + public: + static PassRefPtr<CrossThreadRefCounted<T> > create(T* data) + { + return adoptRef(new CrossThreadRefCounted<T>(data, 0)); + } + + // Used to make an instance that can be used on another thread. + PassRefPtr<CrossThreadRefCounted<T> > crossThreadCopy(); + + void ref(); + void deref(); + T* release(); + + bool isShared() const + { + return !m_refCounter.hasOneRef() || (m_threadSafeRefCounter && !m_threadSafeRefCounter->hasOneRef()); + } + + private: + CrossThreadRefCounted(T* data, ThreadSafeSharedBase* threadedCounter) + : m_threadSafeRefCounter(threadedCounter) + , m_data(data) +#ifndef NDEBUG + , m_threadId(0) +#endif + { + // We use RefCountedBase in an unusual way here, so get rid of the requirement + // that adoptRef be called on it. + m_refCounter.relaxAdoptionRequirement(); + } + + ~CrossThreadRefCounted() + { + if (!m_threadSafeRefCounter) + delete m_data; + } + + void threadSafeDeref(); + +#ifndef NDEBUG + bool isOwnedByCurrentThread() const { return !m_threadId || m_threadId == currentThread(); } +#endif + + RefCountedBase m_refCounter; + ThreadSafeSharedBase* m_threadSafeRefCounter; + T* m_data; +#ifndef NDEBUG + ThreadIdentifier m_threadId; +#endif + }; + + template<class T> + void CrossThreadRefCounted<T>::ref() + { + ASSERT(isOwnedByCurrentThread()); + m_refCounter.ref(); +#ifndef NDEBUG + // Store the threadId as soon as the ref count gets to 2. + // The class gets created with a ref count of 1 and then passed + // to another thread where to ref count get increased. This + // is a heuristic but it seems to always work and has helped + // find some bugs. + if (!m_threadId && m_refCounter.refCount() == 2) + m_threadId = currentThread(); +#endif + } + + template<class T> + void CrossThreadRefCounted<T>::deref() + { + ASSERT(isOwnedByCurrentThread()); + if (m_refCounter.derefBase()) { + threadSafeDeref(); + delete this; + } else { +#ifndef NDEBUG + // Clear the threadId when the ref goes to 1 because it + // is safe to be passed to another thread at this point. + if (m_threadId && m_refCounter.refCount() == 1) + m_threadId = 0; +#endif + } + } + + template<class T> + T* CrossThreadRefCounted<T>::release() + { + ASSERT(!isShared()); + + T* data = m_data; + m_data = 0; + return data; + } + + template<class T> + PassRefPtr<CrossThreadRefCounted<T> > CrossThreadRefCounted<T>::crossThreadCopy() + { + ASSERT(isOwnedByCurrentThread()); + if (m_threadSafeRefCounter) + m_threadSafeRefCounter->ref(); + else + m_threadSafeRefCounter = new ThreadSafeSharedBase(2); + + return adoptRef(new CrossThreadRefCounted<T>(m_data, m_threadSafeRefCounter)); + } + + + template<class T> + void CrossThreadRefCounted<T>::threadSafeDeref() + { + if (m_threadSafeRefCounter && m_threadSafeRefCounter->derefBase()) { + delete m_threadSafeRefCounter; + m_threadSafeRefCounter = 0; + } + } +} // namespace WTF + +using WTF::CrossThreadRefCounted; + +#endif // CrossThreadRefCounted_h |