Line data Source code
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 "mozilla/dom/cache/Types.h"
11 : #include "nsCOMPtr.h"
12 : #include "nsISupportsImpl.h"
13 : #include "nsProxyRelease.h"
14 : #include "nsString.h"
15 : #include "nsTArray.h"
16 : #include "nsTObserverArray.h"
17 :
18 : class nsIEventTarget;
19 : class nsIThread;
20 :
21 : namespace mozilla {
22 : namespace dom {
23 :
24 : namespace quota {
25 :
26 : class DirectoryLock;
27 :
28 : } // namespace quota
29 :
30 : namespace cache {
31 :
32 : class Action;
33 : class Manager;
34 :
35 : // The Context class is RAII-style class for managing IO operations within the
36 : // Cache.
37 : //
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:
45 : //
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::AbortOperations() which
51 : // in turn cancels all existing Action objects and then marks the Manager
52 : // as invalid.
53 : // 3) Browser shutdown occurs and the Manager calls Context::CancelAll().
54 : //
55 : // In either case, though, the Action objects must be destroyed first to
56 : // allow the Context to be destroyed.
57 : //
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.
61 : //
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
66 : {
67 : typedef mozilla::dom::quota::DirectoryLock DirectoryLock;
68 :
69 : public:
70 : // Define a class allowing other threads to hold the Context alive. This also
71 : // allows these other threads to safely close or cancel the Context.
72 : class ThreadsafeHandle final
73 : {
74 : friend class Context;
75 : public:
76 : void AllowToClose();
77 : void InvalidateAndAllowToClose();
78 : private:
79 : explicit ThreadsafeHandle(Context* aContext);
80 : ~ThreadsafeHandle();
81 :
82 : // disallow copying
83 : ThreadsafeHandle(const ThreadsafeHandle&) = delete;
84 : ThreadsafeHandle& operator=(const ThreadsafeHandle&) = delete;
85 :
86 : void AllowToCloseOnOwningThread();
87 : void InvalidateAndAllowToCloseOnOwningThread();
88 :
89 : void ContextDestroyed(Context* aContext);
90 :
91 : // Cleared to allow the Context to close. Only safe to access on
92 : // owning thread.
93 : RefPtr<Context> mStrongRef;
94 :
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.
98 : Context* mWeakRef;
99 :
100 : nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
101 :
102 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(cache::Context::ThreadsafeHandle)
103 : };
104 :
105 : // Different objects hold references to the Context while some work is being
106 : // performed asynchronously. These objects must implement the Activity
107 : // interface and register themselves with the AddActivity(). When they are
108 : // destroyed they must call RemoveActivity(). This allows the Context to
109 : // cancel any outstanding Activity work when the Context is cancelled.
110 0 : class Activity
111 : {
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 already_AddRefed<Context>
121 : Create(Manager* aManager, nsISerialEventTarget* aTarget,
122 : Action* aInitAction, Context* aOldContext);
123 :
124 : // Execute given action on the target once the quota manager has been
125 : // initialized.
126 : //
127 : // Only callable from the thread that created the Context.
128 : void Dispatch(Action* aAction);
129 :
130 : // Cancel any Actions running or waiting to run. This should allow the
131 : // Context to be released and Listener::RemoveContext() will be called
132 : // when complete.
133 : //
134 : // Only callable from the thread that created the Context.
135 : void CancelAll();
136 :
137 : // True if CancelAll() has been called.
138 : bool IsCanceled() const;
139 :
140 : // Like CancelAll(), but also marks the Manager as "invalid".
141 : void Invalidate();
142 :
143 : // Remove any self references and allow the Context to be released when
144 : // there are no more Actions to process.
145 : void AllowToClose();
146 :
147 : // Cancel any Actions running or waiting to run that operate on the given
148 : // cache ID.
149 : //
150 : // Only callable from the thread that created the Context.
151 : void CancelForCacheId(CacheId aCacheId);
152 :
153 : void AddActivity(Activity* aActivity);
154 : void RemoveActivity(Activity* aActivity);
155 :
156 : const QuotaInfo&
157 : GetQuotaInfo() const
158 : {
159 : return mQuotaInfo;
160 : }
161 :
162 : // Tell the Context that some state information has been orphaned in the
163 : // data store and won't be cleaned up. The Context will leave the marker
164 : // in place to trigger cleanup the next times its opened.
165 : void NoteOrphanedData();
166 :
167 : private:
168 : class Data;
169 : class QuotaInitRunnable;
170 : class ActionRunnable;
171 :
172 : enum State
173 : {
174 : STATE_CONTEXT_PREINIT,
175 : STATE_CONTEXT_INIT,
176 : STATE_CONTEXT_READY,
177 : STATE_CONTEXT_CANCELED
178 : };
179 :
180 0 : struct PendingAction
181 : {
182 : nsCOMPtr<nsIEventTarget> mTarget;
183 : RefPtr<Action> mAction;
184 : };
185 :
186 : Context(Manager* aManager, nsISerialEventTarget* aTarget, Action* aInitAction);
187 : ~Context();
188 : void Init(Context* aOldContext);
189 : void Start();
190 : void DispatchAction(Action* aAction, bool aDoomData = false);
191 : void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
192 : already_AddRefed<DirectoryLock> aDirectoryLock);
193 :
194 :
195 : already_AddRefed<ThreadsafeHandle>
196 : CreateThreadsafeHandle();
197 :
198 : void
199 : SetNextContext(Context* aNextContext);
200 :
201 : void
202 : DoomTargetData();
203 :
204 : RefPtr<Manager> mManager;
205 : nsCOMPtr<nsISerialEventTarget> mTarget;
206 : RefPtr<Data> mData;
207 : State mState;
208 : bool mOrphanedData;
209 : QuotaInfo mQuotaInfo;
210 : RefPtr<QuotaInitRunnable> mInitRunnable;
211 : RefPtr<Action> mInitAction;
212 : nsTArray<PendingAction> mPendingActions;
213 :
214 : // Weak refs since activites must remove themselves from this list before
215 : // being destroyed by calling RemoveActivity().
216 : typedef nsTObserverArray<Activity*> ActivityList;
217 : ActivityList mActivityList;
218 :
219 : // The ThreadsafeHandle may have a strong ref back to us. This creates
220 : // a ref-cycle that keeps the Context alive. The ref-cycle is broken
221 : // when ThreadsafeHandle::AllowToClose() is called.
222 : RefPtr<ThreadsafeHandle> mThreadsafeHandle;
223 :
224 : RefPtr<DirectoryLock> mDirectoryLock;
225 : RefPtr<Context> mNextContext;
226 :
227 : public:
228 0 : NS_INLINE_DECL_REFCOUNTING(cache::Context)
229 : };
230 :
231 : } // namespace cache
232 : } // namespace dom
233 : } // namespace mozilla
234 :
235 : #endif // mozilla_dom_cache_Context_h
|