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