JavaScriptCore/wtf/CrossThreadRefCounted.h
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 namespace WTF {
       
    40 
       
    41     // Used to allowing sharing data across classes and threads (like ThreadedSafeShared).
       
    42     //
       
    43     // Why not just use ThreadSafeShared?
       
    44     // ThreadSafeShared can have a significant perf impact when used in low level classes
       
    45     // (like UString) that get ref/deref'ed a lot. This class has the benefit of doing fast ref
       
    46     // counts like RefPtr whenever possible, but it has the downside that you need to copy it
       
    47     // to use it on another thread.
       
    48     //
       
    49     // Is this class threadsafe?
       
    50     // While each instance of the class is not threadsafe, the copied instance is threadsafe
       
    51     // with respect to the original and any other copies.  The underlying m_data is jointly
       
    52     // owned by the original instance and all copies.
       
    53     template<class T>
       
    54     class CrossThreadRefCounted : public Noncopyable {
       
    55     public:
       
    56         static PassRefPtr<CrossThreadRefCounted<T> > create(T* data)
       
    57         {
       
    58             return adoptRef(new CrossThreadRefCounted<T>(data, 0));
       
    59         }
       
    60 
       
    61         // Used to make an instance that can be used on another thread.
       
    62         PassRefPtr<CrossThreadRefCounted<T> > crossThreadCopy();
       
    63 
       
    64         void ref();
       
    65         void deref();
       
    66         T* release();
       
    67 
       
    68         bool isShared() const
       
    69         {
       
    70             return !m_refCounter.hasOneRef() || (m_threadSafeRefCounter && !m_threadSafeRefCounter->hasOneRef());
       
    71         }
       
    72 
       
    73     private:
       
    74         CrossThreadRefCounted(T* data, ThreadSafeSharedBase* threadedCounter)
       
    75             : m_threadSafeRefCounter(threadedCounter)
       
    76             , m_data(data)
       
    77 #ifndef NDEBUG
       
    78             , m_threadId(0)
       
    79 #endif
       
    80         {
       
    81             // We use RefCountedBase in an unusual way here, so get rid of the requirement
       
    82             // that adoptRef be called on it.
       
    83             m_refCounter.relaxAdoptionRequirement();
       
    84         }
       
    85 
       
    86         ~CrossThreadRefCounted()
       
    87         {
       
    88             if (!m_threadSafeRefCounter)
       
    89                 delete m_data;
       
    90         }
       
    91 
       
    92         void threadSafeDeref();
       
    93 
       
    94 #ifndef NDEBUG
       
    95         bool isOwnedByCurrentThread() const { return !m_threadId || m_threadId == currentThread(); }
       
    96 #endif
       
    97 
       
    98         RefCountedBase m_refCounter;
       
    99         ThreadSafeSharedBase* m_threadSafeRefCounter;
       
   100         T* m_data;
       
   101 #ifndef NDEBUG
       
   102         ThreadIdentifier m_threadId;
       
   103 #endif
       
   104     };
       
   105 
       
   106     template<class T>
       
   107     void CrossThreadRefCounted<T>::ref()
       
   108     {
       
   109         ASSERT(isOwnedByCurrentThread());
       
   110         m_refCounter.ref();
       
   111 #ifndef NDEBUG
       
   112         // Store the threadId as soon as the ref count gets to 2.
       
   113         // The class gets created with a ref count of 1 and then passed
       
   114         // to another thread where to ref count get increased.  This
       
   115         // is a heuristic but it seems to always work and has helped
       
   116         // find some bugs.
       
   117         if (!m_threadId && m_refCounter.refCount() == 2)
       
   118             m_threadId = currentThread();
       
   119 #endif
       
   120     }
       
   121 
       
   122     template<class T>
       
   123     void CrossThreadRefCounted<T>::deref()
       
   124     {
       
   125         ASSERT(isOwnedByCurrentThread());
       
   126         if (m_refCounter.derefBase()) {
       
   127             threadSafeDeref();
       
   128             delete this;
       
   129         } else {
       
   130 #ifndef NDEBUG
       
   131             // Clear the threadId when the ref goes to 1 because it
       
   132             // is safe to be passed to another thread at this point.
       
   133             if (m_threadId && m_refCounter.refCount() == 1)
       
   134                 m_threadId = 0;
       
   135 #endif
       
   136         }
       
   137     }
       
   138 
       
   139     template<class T>
       
   140     T* CrossThreadRefCounted<T>::release()
       
   141     {
       
   142         ASSERT(!isShared());
       
   143 
       
   144         T* data = m_data;
       
   145         m_data = 0;
       
   146         return data;
       
   147     }
       
   148 
       
   149     template<class T>
       
   150     PassRefPtr<CrossThreadRefCounted<T> > CrossThreadRefCounted<T>::crossThreadCopy()
       
   151     {
       
   152         ASSERT(isOwnedByCurrentThread());
       
   153         if (m_threadSafeRefCounter)
       
   154             m_threadSafeRefCounter->ref();
       
   155         else
       
   156             m_threadSafeRefCounter = new ThreadSafeSharedBase(2);
       
   157 
       
   158         return adoptRef(new CrossThreadRefCounted<T>(m_data, m_threadSafeRefCounter));
       
   159     }
       
   160 
       
   161 
       
   162     template<class T>
       
   163     void CrossThreadRefCounted<T>::threadSafeDeref()
       
   164     {
       
   165         if (m_threadSafeRefCounter && m_threadSafeRefCounter->derefBase()) {
       
   166             delete m_threadSafeRefCounter;
       
   167             m_threadSafeRefCounter = 0;
       
   168         }
       
   169     }
       
   170 } // namespace WTF
       
   171 
       
   172 using WTF::CrossThreadRefCounted;
       
   173 
       
   174 #endif // CrossThreadRefCounted_h