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