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"
13 #include "nsISupportsImpl.h"
14 #include "nsProxyRelease.h"
17 #include "nsTObserverArray.h"
22 namespace mozilla::dom
{
35 // The Context class is RAII-style class for managing IO operations within the
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
;
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
> {
75 explicit ThreadsafeHandle(SafeRefPtr
<Context
> aContext
);
78 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context::ThreadsafeHandle
)
81 void InvalidateAndAllowToClose();
84 void AllowToCloseOnOwningThread();
85 void InvalidateAndAllowToCloseOnOwningThread();
87 void ContextDestroyed(Context
& aContext
);
89 // Cleared to allow the Context to close. Only safe to access on
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.
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.
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
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
132 // Only callable from the thread that created the Context.
135 // True if CancelAll() has been called.
136 bool IsCanceled() const;
138 // Like CancelAll(), but also marks the Manager as "invalid".
141 // Remove any self references and allow the Context to be released when
142 // there are no more Actions to process.
145 // Cancel any Actions running or waiting to run that operate on the given
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();
161 class QuotaInitRunnable
;
162 class ActionRunnable
;
165 STATE_CONTEXT_PREINIT
,
168 STATE_CONTEXT_CANCELED
171 struct PendingAction
{
172 nsCOMPtr
<nsIEventTarget
> mTarget
;
173 SafeRefPtr
<Action
> mAction
;
176 void Init(Maybe
<Context
&> aOldContext
);
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
;
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
;
212 // XXX Consider adding a private guard parameter.
213 Context(SafeRefPtr
<Manager
> aManager
, nsISerialEventTarget
* aTarget
,
214 SafeRefPtr
<Action
> aInitAction
);
218 MOZ_DECLARE_REFCOUNTED_TYPENAME(cache::Context
)
222 } // namespace mozilla::dom
224 #endif // mozilla_dom_cache_Context_h