LCOV - code coverage report
Current view: top level - xpcom/threads - StateMirroring.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 122 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 438 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #if !defined(StateMirroring_h_)
       8             : #define StateMirroring_h_
       9             : 
      10             : #include "mozilla/Maybe.h"
      11             : #include "mozilla/MozPromise.h"
      12             : #include "mozilla/StateWatching.h"
      13             : #include "mozilla/TaskDispatcher.h"
      14             : #include "mozilla/UniquePtr.h"
      15             : #include "mozilla/Unused.h"
      16             : 
      17             : #include "mozilla/Logging.h"
      18             : #include "nsISupportsImpl.h"
      19             : 
      20             : /*
      21             :  * The state-mirroring machinery allows pieces of interesting state to be
      22             :  * observed on multiple thread without locking. The basic strategy is to track
      23             :  * changes in a canonical value and post updates to other threads that hold
      24             :  * mirrors for that value.
      25             :  *
      26             :  * One problem with the naive implementation of such a system is that some pieces
      27             :  * of state need to be updated atomically, and certain other operations need to
      28             :  * wait for these atomic updates to complete before executing. The state-mirroring
      29             :  * machinery solves this problem by requiring that its owner thread uses tail
      30             :  * dispatch, and posting state update events (which should always be run first by
      31             :  * TaskDispatcher implementations) to that tail dispatcher. This ensures that
      32             :  * state changes are always atomic from the perspective of observing threads.
      33             :  *
      34             :  * Given that state-mirroring is an automatic background process, we try to avoid
      35             :  * burdening the caller with worrying too much about teardown. To that end, we
      36             :  * don't assert dispatch success for any of the notifications, and assume that
      37             :  * any canonical or mirror owned by a thread for whom dispatch fails will soon
      38             :  * be disconnected by its holder anyway.
      39             :  *
      40             :  * Given that semantics may change and comments tend to go out of date, we
      41             :  * deliberately don't provide usage examples here. Grep around to find them.
      42             :  */
      43             : 
      44             : namespace mozilla {
      45             : 
      46             : // Mirror<T> and Canonical<T> inherit WatchTarget, so we piggy-back on the
      47             : // logging that WatchTarget already does. Given that, it makes sense to share
      48             : // the same log module.
      49             : #define MIRROR_LOG(x, ...) \
      50             :   MOZ_ASSERT(gStateWatchingLog); \
      51             :   MOZ_LOG(gStateWatchingLog, LogLevel::Debug, (x, ##__VA_ARGS__))
      52             : 
      53             : template<typename T> class AbstractMirror;
      54             : 
      55             : /*
      56             :  * AbstractCanonical is a superclass from which all Canonical values must
      57             :  * inherit. It serves as the interface of operations which may be performed (via
      58             :  * asynchronous dispatch) by other threads, in particular by the corresponding
      59             :  * Mirror value.
      60             :  */
      61             : template<typename T>
      62             : class AbstractCanonical
      63             : {
      64             : public:
      65           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractCanonical)
      66           0 :   AbstractCanonical(AbstractThread* aThread) : mOwnerThread(aThread) {}
      67             :   virtual void AddMirror(AbstractMirror<T>* aMirror) = 0;
      68             :   virtual void RemoveMirror(AbstractMirror<T>* aMirror) = 0;
      69             : 
      70           0 :   AbstractThread* OwnerThread() const { return mOwnerThread; }
      71             : protected:
      72           0 :   virtual ~AbstractCanonical() {}
      73             :   RefPtr<AbstractThread> mOwnerThread;
      74             : };
      75             : 
      76             : /*
      77             :  * AbstractMirror is a superclass from which all Mirror values must
      78             :  * inherit. It serves as the interface of operations which may be performed (via
      79             :  * asynchronous dispatch) by other threads, in particular by the corresponding
      80             :  * Canonical value.
      81             :  */
      82             : template<typename T>
      83             : class AbstractMirror
      84             : {
      85             : public:
      86           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractMirror)
      87           0 :   AbstractMirror(AbstractThread* aThread) : mOwnerThread(aThread) {}
      88             :   virtual void UpdateValue(const T& aNewValue) = 0;
      89             :   virtual void NotifyDisconnected() = 0;
      90             : 
      91           0 :   AbstractThread* OwnerThread() const { return mOwnerThread; }
      92             : protected:
      93           0 :   virtual ~AbstractMirror() {}
      94             :   RefPtr<AbstractThread> mOwnerThread;
      95             : };
      96             : 
      97             : /*
      98             :  * Canonical<T> is a wrapper class that allows a given value to be mirrored by other
      99             :  * threads. It maintains a list of active mirrors, and queues updates for them
     100             :  * when the internal value changes. When changing the value, the caller needs to
     101             :  * pass a TaskDispatcher object, which fires the updates at the appropriate time.
     102             :  * Canonical<T> is also a WatchTarget, and may be set up to trigger other routines
     103             :  * (on the same thread) when the canonical value changes.
     104             :  *
     105             :  * Canonical<T> is intended to be used as a member variable, so it doesn't actually
     106             :  * inherit AbstractCanonical<T> (a refcounted type). Rather, it contains an inner
     107             :  * class called |Impl| that implements most of the interesting logic.
     108             :  */
     109             : template<typename T>
     110             : class Canonical
     111             : {
     112             : public:
     113           0 :   Canonical(AbstractThread* aThread, const T& aInitialValue, const char* aName)
     114           0 :   {
     115           0 :     mImpl = new Impl(aThread, aInitialValue, aName);
     116           0 :   }
     117             : 
     118             : 
     119           0 :   ~Canonical() {}
     120             : 
     121             : private:
     122             :   class Impl : public AbstractCanonical<T>, public WatchTarget
     123             :   {
     124             :   public:
     125             :     using AbstractCanonical<T>::OwnerThread;
     126             : 
     127           0 :     Impl(AbstractThread* aThread, const T& aInitialValue, const char* aName)
     128           0 :       : AbstractCanonical<T>(aThread), WatchTarget(aName), mValue(aInitialValue)
     129             :     {
     130           0 :       MIRROR_LOG("%s [%p] initialized", mName, this);
     131           0 :       MOZ_ASSERT(aThread->SupportsTailDispatch(), "Can't get coherency without tail dispatch");
     132           0 :     }
     133             : 
     134           0 :     void AddMirror(AbstractMirror<T>* aMirror) override
     135             :     {
     136           0 :       MIRROR_LOG("%s [%p] adding mirror %p", mName, this, aMirror);
     137           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     138           0 :       MOZ_ASSERT(!mMirrors.Contains(aMirror));
     139           0 :       mMirrors.AppendElement(aMirror);
     140           0 :       aMirror->OwnerThread()->DispatchStateChange(MakeNotifier(aMirror));
     141           0 :     }
     142             : 
     143           0 :     void RemoveMirror(AbstractMirror<T>* aMirror) override
     144             :     {
     145           0 :       MIRROR_LOG("%s [%p] removing mirror %p", mName, this, aMirror);
     146           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     147           0 :       MOZ_ASSERT(mMirrors.Contains(aMirror));
     148           0 :       mMirrors.RemoveElement(aMirror);
     149           0 :     }
     150             : 
     151           0 :     void DisconnectAll()
     152             :     {
     153           0 :       MIRROR_LOG("%s [%p] Disconnecting all mirrors", mName, this);
     154           0 :       for (size_t i = 0; i < mMirrors.Length(); ++i) {
     155           0 :         mMirrors[i]->OwnerThread()->Dispatch(
     156             :           NewRunnableMethod("AbstractMirror::NotifyDisconnected",
     157           0 :                             mMirrors[i],
     158             :                             &AbstractMirror<T>::NotifyDisconnected),
     159             :           AbstractThread::DontAssertDispatchSuccess);
     160             :       }
     161           0 :       mMirrors.Clear();
     162           0 :     }
     163             : 
     164           0 :     operator const T&()
     165             :     {
     166           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     167           0 :       return mValue;
     168             :     }
     169             : 
     170           0 :     void Set(const T& aNewValue)
     171             :     {
     172           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     173             : 
     174           0 :       if (aNewValue == mValue) {
     175           0 :         return;
     176             :       }
     177             : 
     178             :       // Notify same-thread watchers. The state watching machinery will make sure
     179             :       // that notifications run at the right time.
     180           0 :       NotifyWatchers();
     181             : 
     182             :       // Check if we've already got a pending update. If so we won't schedule another
     183             :       // one.
     184           0 :       bool alreadyNotifying = mInitialValue.isSome();
     185             : 
     186             :       // Stash the initial value if needed, then update to the new value.
     187           0 :       if (mInitialValue.isNothing()) {
     188           0 :         mInitialValue.emplace(mValue);
     189             :       }
     190           0 :       mValue = aNewValue;
     191             : 
     192             :       // We wait until things have stablized before sending state updates so that
     193             :       // we can avoid sending multiple updates, and possibly avoid sending any
     194             :       // updates at all if the value ends up where it started.
     195           0 :       if (!alreadyNotifying) {
     196           0 :         AbstractThread::DispatchDirectTask(NewRunnableMethod(
     197             :           "Canonical::Impl::DoNotify", this, &Impl::DoNotify));
     198             :       }
     199             :     }
     200             : 
     201             :     Impl& operator=(const T& aNewValue) { Set(aNewValue); return *this; }
     202             :     Impl& operator=(const Impl& aOther) { Set(aOther); return *this; }
     203             :     Impl(const Impl& aOther) = delete;
     204             : 
     205             :   protected:
     206           0 :     ~Impl() { MOZ_DIAGNOSTIC_ASSERT(mMirrors.IsEmpty()); }
     207             : 
     208             :   private:
     209           0 :     void DoNotify()
     210             :     {
     211           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     212           0 :       MOZ_ASSERT(mInitialValue.isSome());
     213           0 :       bool same = mInitialValue.ref() == mValue;
     214           0 :       mInitialValue.reset();
     215             : 
     216           0 :       if (same) {
     217           0 :         MIRROR_LOG("%s [%p] unchanged - not sending update", mName, this);
     218           0 :         return;
     219             :       }
     220             : 
     221           0 :       for (size_t i = 0; i < mMirrors.Length(); ++i) {
     222           0 :         mMirrors[i]->OwnerThread()->DispatchStateChange(MakeNotifier(mMirrors[i]));
     223             :       }
     224             :     }
     225             : 
     226           0 :     already_AddRefed<nsIRunnable> MakeNotifier(AbstractMirror<T>* aMirror)
     227             :     {
     228             :       return NewRunnableMethod<T>("AbstractMirror::UpdateValue",
     229             :                                   aMirror,
     230             :                                   &AbstractMirror<T>::UpdateValue,
     231           0 :                                   mValue);
     232             :       ;
     233             :     }
     234             : 
     235             :     T mValue;
     236             :     Maybe<T> mInitialValue;
     237             :     nsTArray<RefPtr<AbstractMirror<T>>> mMirrors;
     238             :   };
     239             : public:
     240             : 
     241             :   // NB: Because mirror-initiated disconnection can race with canonical-
     242             :   // initiated disconnection, a canonical should never be reinitialized.
     243             :   // Forward control operations to the Impl.
     244           0 :   void DisconnectAll() { return mImpl->DisconnectAll(); }
     245             : 
     246             :   // Access to the Impl.
     247           0 :   operator Impl&() { return *mImpl; }
     248           0 :   Impl* operator&() { return mImpl; }
     249             : 
     250             :   // Access to the T.
     251           0 :   const T& Ref() const { return *mImpl; }
     252           0 :   operator const T&() const { return Ref(); }
     253           0 :   void Set(const T& aNewValue) { mImpl->Set(aNewValue); }
     254           0 :   Canonical& operator=(const T& aNewValue) { Set(aNewValue); return *this; }
     255             :   Canonical& operator=(const Canonical& aOther) { Set(aOther); return *this; }
     256             :   Canonical(const Canonical& aOther) = delete;
     257             : 
     258             : private:
     259             :   RefPtr<Impl> mImpl;
     260             : };
     261             : 
     262             : /*
     263             :  * Mirror<T> is a wrapper class that allows a given value to mirror that of a
     264             :  * Canonical<T> owned by another thread. It registers itself with a Canonical<T>,
     265             :  * and is periodically updated with new values. Mirror<T> is also a WatchTarget,
     266             :  * and may be set up to trigger other routines (on the same thread) when the
     267             :  * mirrored value changes.
     268             :  *
     269             :  * Mirror<T> is intended to be used as a member variable, so it doesn't actually
     270             :  * inherit AbstractMirror<T> (a refcounted type). Rather, it contains an inner
     271             :  * class called |Impl| that implements most of the interesting logic.
     272             :  */
     273             : template<typename T>
     274             : class Mirror
     275             : {
     276             : public:
     277           0 :   Mirror(AbstractThread* aThread, const T& aInitialValue, const char* aName)
     278           0 :   {
     279           0 :     mImpl = new Impl(aThread, aInitialValue, aName);
     280           0 :   }
     281             : 
     282           0 :   ~Mirror()
     283             :   {
     284             :     // As a member of complex objects, a Mirror<T> may be destroyed on a
     285             :     // different thread than its owner, or late in shutdown during CC. Given
     286             :     // that, we require manual disconnection so that callers can put things in
     287             :     // the right place.
     288           0 :     MOZ_DIAGNOSTIC_ASSERT(!mImpl->IsConnected());
     289           0 :   }
     290             : 
     291             : private:
     292             :   class Impl : public AbstractMirror<T>, public WatchTarget
     293             :   {
     294             :   public:
     295             :     using AbstractMirror<T>::OwnerThread;
     296             : 
     297           0 :     Impl(AbstractThread* aThread, const T& aInitialValue, const char* aName)
     298           0 :       : AbstractMirror<T>(aThread), WatchTarget(aName), mValue(aInitialValue)
     299             :     {
     300           0 :       MIRROR_LOG("%s [%p] initialized", mName, this);
     301           0 :       MOZ_ASSERT(aThread->SupportsTailDispatch(), "Can't get coherency without tail dispatch");
     302           0 :     }
     303             : 
     304           0 :     operator const T&()
     305             :     {
     306           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     307           0 :       return mValue;
     308             :     }
     309             : 
     310           0 :     virtual void UpdateValue(const T& aNewValue) override
     311             :     {
     312           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     313           0 :       if (mValue != aNewValue) {
     314           0 :         mValue = aNewValue;
     315           0 :         WatchTarget::NotifyWatchers();
     316             :       }
     317           0 :     }
     318             : 
     319           0 :     virtual void NotifyDisconnected() override
     320             :     {
     321           0 :       MIRROR_LOG("%s [%p] Notifed of disconnection from %p", mName, this, mCanonical.get());
     322           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     323           0 :       mCanonical = nullptr;
     324           0 :     }
     325             : 
     326           0 :     bool IsConnected() const { return !!mCanonical; }
     327             : 
     328           0 :     void Connect(AbstractCanonical<T>* aCanonical)
     329             :     {
     330           0 :       MIRROR_LOG("%s [%p] Connecting to %p", mName, this, aCanonical);
     331           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     332           0 :       MOZ_ASSERT(!IsConnected());
     333           0 :       MOZ_ASSERT(OwnerThread()->RequiresTailDispatch(aCanonical->OwnerThread()), "Can't get coherency without tail dispatch");
     334             : 
     335             :       nsCOMPtr<nsIRunnable> r =
     336             :         NewRunnableMethod<StoreRefPtrPassByPtr<AbstractMirror<T>>>(
     337             :           "AbstractCanonical::AddMirror",
     338             :           aCanonical,
     339             :           &AbstractCanonical<T>::AddMirror,
     340           0 :           this);
     341           0 :       aCanonical->OwnerThread()->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess);
     342           0 :       mCanonical = aCanonical;
     343           0 :     }
     344             :   public:
     345             : 
     346           0 :     void DisconnectIfConnected()
     347             :     {
     348           0 :       MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
     349           0 :       if (!IsConnected()) {
     350           0 :         return;
     351             :       }
     352             : 
     353           0 :       MIRROR_LOG("%s [%p] Disconnecting from %p", mName, this, mCanonical.get());
     354             :       nsCOMPtr<nsIRunnable> r =
     355             :         NewRunnableMethod<StoreRefPtrPassByPtr<AbstractMirror<T>>>(
     356             :           "AbstractCanonical::RemoveMirror",
     357             :           mCanonical,
     358             :           &AbstractCanonical<T>::RemoveMirror,
     359           0 :           this);
     360           0 :       mCanonical->OwnerThread()->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess);
     361           0 :       mCanonical = nullptr;
     362             :     }
     363             : 
     364             :   protected:
     365           0 :     ~Impl() { MOZ_DIAGNOSTIC_ASSERT(!IsConnected()); }
     366             : 
     367             :   private:
     368             :     T mValue;
     369             :     RefPtr<AbstractCanonical<T>> mCanonical;
     370             :   };
     371             : public:
     372             : 
     373             :   // Forward control operations to the Impl<T>.
     374           0 :   void Connect(AbstractCanonical<T>* aCanonical) { mImpl->Connect(aCanonical); }
     375           0 :   void DisconnectIfConnected() { mImpl->DisconnectIfConnected(); }
     376             : 
     377             :   // Access to the Impl<T>.
     378           0 :   operator Impl&() { return *mImpl; }
     379             :   Impl* operator&() { return mImpl; }
     380             : 
     381             :   // Access to the T.
     382           0 :   const T& Ref() const { return *mImpl; }
     383           0 :   operator const T&() const { return Ref(); }
     384             : 
     385             : private:
     386             :   RefPtr<Impl> mImpl;
     387             : };
     388             : 
     389             : #undef MIRROR_LOG
     390             : 
     391             : } // namespace mozilla
     392             : 
     393             : #endif

Generated by: LCOV version 1.13