Context.h (8417B)
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 #ifndef mozilla_dom_cache_Context_h 8 #define mozilla_dom_cache_Context_h 9 10 #include "CacheCipherKeyManager.h" 11 #include "mozilla/dom/SafeRefPtr.h" 12 #include "mozilla/dom/cache/Types.h" 13 #include "mozilla/dom/quota/ClientDirectoryLockHandle.h" 14 #include "mozilla/dom/quota/StringifyUtils.h" 15 #include "nsCOMPtr.h" 16 #include "nsISupportsImpl.h" 17 #include "nsProxyRelease.h" 18 #include "nsString.h" 19 #include "nsTArray.h" 20 #include "nsTObserverArray.h" 21 22 class nsIEventTarget; 23 class nsIThread; 24 25 namespace mozilla::dom { 26 27 namespace quota { 28 29 class ClientDirectoryLock; 30 31 } // namespace quota 32 33 namespace cache { 34 35 class Action; 36 class Manager; 37 38 // The Context class is RAII-style class for managing IO operations within the 39 // Cache. 40 // 41 // When a Context is created it performs the complicated steps necessary to 42 // initialize the QuotaManager. Action objects dispatched on the Context are 43 // delayed until this initialization is complete. They are then allow to 44 // execute on any specified thread. Once all references to the Context are 45 // gone, then the steps necessary to release the QuotaManager are performed. 46 // After initialization the Context holds a self reference, so it will stay 47 // alive until one of three conditions occur: 48 // 49 // 1) The Manager will call Context::AllowToClose() when all of the actors 50 // have removed themselves as listener. This means an idle context with 51 // no active DOM objects will close gracefully. 52 // 2) The QuotaManager aborts all operations so it can delete the files. 53 // In this case the QuotaManager calls Client::AbortOperationsForLocks() 54 // which in turn cancels all existing Action objects and then marks the 55 // Manager as invalid. 56 // 3) Browser shutdown occurs and the Manager calls Context::CancelAll(). 57 // 58 // In either case, though, the Action objects must be destroyed first to 59 // allow the Context to be destroyed. 60 // 61 // While the Context performs operations asynchronously on threads, all of 62 // methods in its public interface must be called on the same thread 63 // originally used to create the Context. 64 // 65 // As an invariant, all Context objects must be destroyed before permitting 66 // the "profile-before-change" shutdown event to complete. This is ensured 67 // via the code in ShutdownObserver.cpp. 68 class Context final : public SafeRefCounted<Context>, public Stringifyable { 69 using ClientDirectoryLock = mozilla::dom::quota::ClientDirectoryLock; 70 using ClientDirectoryLockHandle = 71 mozilla::dom::quota::ClientDirectoryLockHandle; 72 73 public: 74 // Define a class allowing other threads to hold the Context alive. This also 75 // allows these other threads to safely close or cancel the Context. 76 class ThreadsafeHandle final : public AtomicSafeRefCounted<ThreadsafeHandle> { 77 friend class Context; 78 79 public: 80 explicit ThreadsafeHandle(SafeRefPtr<Context> aContext); 81 ~ThreadsafeHandle(); 82 83 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context::ThreadsafeHandle) 84 85 void AllowToClose(); 86 void InvalidateAndAllowToClose(); 87 88 private: 89 void AllowToCloseOnOwningThread(); 90 void InvalidateAndAllowToCloseOnOwningThread(); 91 92 void ContextDestroyed(Context& aContext); 93 94 // Cleared to allow the Context to close. Only safe to access on 95 // owning thread. 96 SafeRefPtr<Context> mStrongRef; 97 98 // Used to support cancelation even while the Context is already allowed 99 // to close. Cleared by ~Context() calling ContextDestroyed(). Only 100 // safe to access on owning thread. 101 Context* mWeakRef; 102 103 nsCOMPtr<nsISerialEventTarget> mOwningEventTarget; 104 }; 105 106 // Different objects hold references to the Context while some work is being 107 // performed asynchronously. These objects must implement the Activity 108 // interface and register themselves with the AddActivity(). When they are 109 // destroyed they must call RemoveActivity(). This allows the Context to 110 // cancel any outstanding Activity work when the Context is cancelled. 111 class Activity : public Stringifyable { 112 public: 113 virtual void Cancel() = 0; 114 virtual bool MatchesCacheId(CacheId aCacheId) const = 0; 115 }; 116 117 // Create a Context attached to the given Manager. The given Action 118 // will run on the QuotaManager IO thread. Note, this Action must 119 // be execute synchronously. 120 static SafeRefPtr<Context> Create(SafeRefPtr<Manager> aManager, 121 nsISerialEventTarget* aTarget, 122 SafeRefPtr<Action> aInitAction, 123 Maybe<Context&> aOldContext); 124 125 // Execute given action on the target once the quota manager has been 126 // initialized. 127 // 128 // Only callable from the thread that created the Context. 129 void Dispatch(SafeRefPtr<Action> aAction); 130 131 Maybe<ClientDirectoryLock&> MaybeDirectoryLockRef() const; 132 133 CipherKeyManager& MutableCipherKeyManagerRef(); 134 135 const Maybe<CacheDirectoryMetadata>& MaybeCacheDirectoryMetadataRef() const; 136 137 // Cancel any Actions running or waiting to run. This should allow the 138 // Context to be released and Listener::RemoveContext() will be called 139 // when complete. 140 // 141 // Only callable from the thread that created the Context. 142 void CancelAll(); 143 144 // True if CancelAll() has been called. 145 bool IsCanceled() const; 146 147 // Like CancelAll(), but also marks the Manager as "invalid". 148 void Invalidate(); 149 150 // Remove any self references and allow the Context to be released when 151 // there are no more Actions to process. 152 void AllowToClose(); 153 154 // Cancel any Actions running or waiting to run that operate on the given 155 // cache ID. 156 // 157 // Only callable from the thread that created the Context. 158 void CancelForCacheId(CacheId aCacheId); 159 160 void AddActivity(Activity& aActivity); 161 void RemoveActivity(Activity& aActivity); 162 163 // Tell the Context that some state information has been orphaned in the 164 // data store and won't be cleaned up. The Context will leave the marker 165 // in place to trigger cleanup the next times its opened. 166 void NoteOrphanedData(); 167 168 private: 169 class Data; 170 class QuotaInitRunnable; 171 class ActionRunnable; 172 173 enum State { 174 STATE_CONTEXT_PREINIT, 175 STATE_CONTEXT_INIT, 176 STATE_CONTEXT_READY, 177 STATE_CONTEXT_CANCELED 178 }; 179 180 struct PendingAction { 181 nsCOMPtr<nsIEventTarget> mTarget; 182 SafeRefPtr<Action> mAction; 183 }; 184 185 void Init(Maybe<Context&> aOldContext); 186 void Start(); 187 void DispatchAction(SafeRefPtr<Action> aAction, bool aDoomData = false); 188 void OnQuotaInit(nsresult aRv, 189 const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata, 190 ClientDirectoryLockHandle aDirectoryLockHandle, 191 RefPtr<CipherKeyManager> aCipherKeyManager); 192 193 SafeRefPtr<ThreadsafeHandle> CreateThreadsafeHandle(); 194 195 void SetNextContext(SafeRefPtr<Context> aNextContext); 196 197 void DoomTargetData(); 198 199 void DoStringify(nsACString& aData) override; 200 201 SafeRefPtr<Manager> mManager; 202 nsCOMPtr<nsISerialEventTarget> mTarget; 203 RefPtr<Data> mData; 204 State mState; 205 bool mOrphanedData; 206 Maybe<CacheDirectoryMetadata> mDirectoryMetadata; 207 RefPtr<QuotaInitRunnable> mInitRunnable; 208 SafeRefPtr<Action> mInitAction; 209 nsTArray<PendingAction> mPendingActions; 210 211 // Weak refs since activites must remove themselves from this list before 212 // being destroyed by calling RemoveActivity(). 213 nsTObserverArray<NotNull<Activity*>> mActivityList; 214 215 // The ThreadsafeHandle may have a strong ref back to us. This creates 216 // a ref-cycle that keeps the Context alive. The ref-cycle is broken 217 // when ThreadsafeHandle::AllowToClose() is called. 218 SafeRefPtr<ThreadsafeHandle> mThreadsafeHandle; 219 220 ClientDirectoryLockHandle mDirectoryLockHandle; 221 RefPtr<CipherKeyManager> mCipherKeyManager; 222 SafeRefPtr<Context> mNextContext; 223 224 public: 225 // XXX Consider adding a private guard parameter. 226 Context(SafeRefPtr<Manager> aManager, nsISerialEventTarget* aTarget, 227 SafeRefPtr<Action> aInitAction); 228 ~Context(); 229 230 NS_DECL_OWNINGTHREAD 231 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context) 232 }; 233 234 } // namespace cache 235 } // namespace mozilla::dom 236 237 #endif // mozilla_dom_cache_Context_h