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 "CacheCipherKeyManager.h"
11 #include "mozilla/dom/SafeRefPtr.h"
12 #include "mozilla/dom/cache/Types.h"
13 #include "mozilla/dom/quota/StringifyUtils.h"
15 #include "nsISupportsImpl.h"
16 #include "nsProxyRelease.h"
19 #include "nsTObserverArray.h"
24 namespace mozilla::dom
{
37 // The Context class is RAII-style class for managing IO operations within the
40 // When a Context is created it performs the complicated steps necessary to
41 // initialize the QuotaManager. Action objects dispatched on the Context are
42 // delayed until this initialization is complete. They are then allow to
43 // execute on any specified thread. Once all references to the Context are
44 // gone, then the steps necessary to release the QuotaManager are performed.
45 // After initialization the Context holds a self reference, so it will stay
46 // alive until one of three conditions occur:
48 // 1) The Manager will call Context::AllowToClose() when all of the actors
49 // have removed themselves as listener. This means an idle context with
50 // no active DOM objects will close gracefully.
51 // 2) The QuotaManager aborts all operations so it can delete the files.
52 // In this case the QuotaManager calls Client::AbortOperationsForLocks()
53 // which in turn cancels all existing Action objects and then marks the
54 // Manager as invalid.
55 // 3) Browser shutdown occurs and the Manager calls Context::CancelAll().
57 // In either case, though, the Action objects must be destroyed first to
58 // allow the Context to be destroyed.
60 // While the Context performs operations asynchronously on threads, all of
61 // methods in its public interface must be called on the same thread
62 // originally used to create the Context.
64 // As an invariant, all Context objects must be destroyed before permitting
65 // the "profile-before-change" shutdown event to complete. This is ensured
66 // via the code in ShutdownObserver.cpp.
67 class Context final
: public SafeRefCounted
<Context
>, public Stringifyable
{
68 using DirectoryLock
= mozilla::dom::quota::DirectoryLock
;
71 // Define a class allowing other threads to hold the Context alive. This also
72 // allows these other threads to safely close or cancel the Context.
73 class ThreadsafeHandle final
: public AtomicSafeRefCounted
<ThreadsafeHandle
> {
77 explicit ThreadsafeHandle(SafeRefPtr
<Context
> aContext
);
80 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context::ThreadsafeHandle
)
83 void InvalidateAndAllowToClose();
86 void AllowToCloseOnOwningThread();
87 void InvalidateAndAllowToCloseOnOwningThread();
89 void ContextDestroyed(Context
& aContext
);
91 // Cleared to allow the Context to close. Only safe to access on
93 SafeRefPtr
<Context
> mStrongRef
;
95 // Used to support cancelation even while the Context is already allowed
96 // to close. Cleared by ~Context() calling ContextDestroyed(). Only
97 // safe to access on owning thread.
100 nsCOMPtr
<nsISerialEventTarget
> mOwningEventTarget
;
103 // Different objects hold references to the Context while some work is being
104 // performed asynchronously. These objects must implement the Activity
105 // interface and register themselves with the AddActivity(). When they are
106 // destroyed they must call RemoveActivity(). This allows the Context to
107 // cancel any outstanding Activity work when the Context is cancelled.
108 class Activity
: public Stringifyable
{
110 virtual void Cancel() = 0;
111 virtual bool MatchesCacheId(CacheId aCacheId
) const = 0;
114 // Create a Context attached to the given Manager. The given Action
115 // will run on the QuotaManager IO thread. Note, this Action must
116 // be execute synchronously.
117 static SafeRefPtr
<Context
> Create(SafeRefPtr
<Manager
> aManager
,
118 nsISerialEventTarget
* aTarget
,
119 SafeRefPtr
<Action
> aInitAction
,
120 Maybe
<Context
&> aOldContext
);
122 // Execute given action on the target once the quota manager has been
125 // Only callable from the thread that created the Context.
126 void Dispatch(SafeRefPtr
<Action
> aAction
);
128 Maybe
<DirectoryLock
&> MaybeDirectoryLockRef() const;
130 CipherKeyManager
& MutableCipherKeyManagerRef();
132 const Maybe
<CacheDirectoryMetadata
>& MaybeCacheDirectoryMetadataRef() const;
134 // Cancel any Actions running or waiting to run. This should allow the
135 // Context to be released and Listener::RemoveContext() will be called
138 // Only callable from the thread that created the Context.
141 // True if CancelAll() has been called.
142 bool IsCanceled() const;
144 // Like CancelAll(), but also marks the Manager as "invalid".
147 // Remove any self references and allow the Context to be released when
148 // there are no more Actions to process.
151 // Cancel any Actions running or waiting to run that operate on the given
154 // Only callable from the thread that created the Context.
155 void CancelForCacheId(CacheId aCacheId
);
157 void AddActivity(Activity
& aActivity
);
158 void RemoveActivity(Activity
& aActivity
);
160 // Tell the Context that some state information has been orphaned in the
161 // data store and won't be cleaned up. The Context will leave the marker
162 // in place to trigger cleanup the next times its opened.
163 void NoteOrphanedData();
167 class QuotaInitRunnable
;
168 class ActionRunnable
;
171 STATE_CONTEXT_PREINIT
,
174 STATE_CONTEXT_CANCELED
177 struct PendingAction
{
178 nsCOMPtr
<nsIEventTarget
> mTarget
;
179 SafeRefPtr
<Action
> mAction
;
182 void Init(Maybe
<Context
&> aOldContext
);
184 void DispatchAction(SafeRefPtr
<Action
> aAction
, bool aDoomData
= false);
185 void OnQuotaInit(nsresult aRv
,
186 const Maybe
<CacheDirectoryMetadata
>& aDirectoryMetadata
,
187 RefPtr
<DirectoryLock
> aDirectoryLock
,
188 RefPtr
<CipherKeyManager
> aCipherKeyManager
);
190 SafeRefPtr
<ThreadsafeHandle
> CreateThreadsafeHandle();
192 void SetNextContext(SafeRefPtr
<Context
> aNextContext
);
194 void DoomTargetData();
196 void DoStringify(nsACString
& aData
) override
;
198 SafeRefPtr
<Manager
> mManager
;
199 nsCOMPtr
<nsISerialEventTarget
> mTarget
;
203 Maybe
<CacheDirectoryMetadata
> mDirectoryMetadata
;
204 RefPtr
<QuotaInitRunnable
> mInitRunnable
;
205 SafeRefPtr
<Action
> mInitAction
;
206 nsTArray
<PendingAction
> mPendingActions
;
208 // Weak refs since activites must remove themselves from this list before
209 // being destroyed by calling RemoveActivity().
210 nsTObserverArray
<NotNull
<Activity
*>> mActivityList
;
212 // The ThreadsafeHandle may have a strong ref back to us. This creates
213 // a ref-cycle that keeps the Context alive. The ref-cycle is broken
214 // when ThreadsafeHandle::AllowToClose() is called.
215 SafeRefPtr
<ThreadsafeHandle
> mThreadsafeHandle
;
217 RefPtr
<DirectoryLock
> mDirectoryLock
;
218 RefPtr
<CipherKeyManager
> mCipherKeyManager
;
219 SafeRefPtr
<Context
> mNextContext
;
222 // XXX Consider adding a private guard parameter.
223 Context(SafeRefPtr
<Manager
> aManager
, nsISerialEventTarget
* aTarget
,
224 SafeRefPtr
<Action
> aInitAction
);
228 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context
)
232 } // namespace mozilla::dom
234 #endif // mozilla_dom_cache_Context_h