dom/workers/WorkerRunnable.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:5e01810194ad
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef mozilla_dom_workers_workerrunnable_h__
7 #define mozilla_dom_workers_workerrunnable_h__
8
9 #include "Workers.h"
10
11 #include "nsICancelableRunnable.h"
12
13 #include "mozilla/Atomics.h"
14 #include "nsISupportsImpl.h"
15
16 class JSContext;
17 class nsIEventTarget;
18
19 BEGIN_WORKERS_NAMESPACE
20
21 class WorkerPrivate;
22
23 // Use this runnable to communicate from the worker to its parent or vice-versa.
24 // The busy count must be taken into consideration and declared at construction
25 // time.
26 class WorkerRunnable : public nsICancelableRunnable
27 {
28 public:
29 enum TargetAndBusyBehavior {
30 // Target the main thread for top-level workers, otherwise target the
31 // WorkerThread of the worker's parent. No change to the busy count.
32 ParentThreadUnchangedBusyCount,
33
34 // Target the thread where the worker event loop runs. The busy count will
35 // be incremented before dispatching and decremented (asynchronously) after
36 // running.
37 WorkerThreadModifyBusyCount,
38
39 // Target the thread where the worker event loop runs. The busy count will
40 // not be modified in any way. Besides worker-internal runnables this is
41 // almost always the wrong choice.
42 WorkerThreadUnchangedBusyCount
43 };
44
45 protected:
46 // The WorkerPrivate that this runnable is associated with.
47 WorkerPrivate* mWorkerPrivate;
48
49 // See above.
50 TargetAndBusyBehavior mBehavior;
51
52 // It's unclear whether or not Cancel() is supposed to work when called on any
53 // thread. To be safe we're using an atomic but it's likely overkill.
54 Atomic<uint32_t> mCanceled;
55
56 private:
57 // Whether or not Cancel() is currently being called from inside the Run()
58 // method. Avoids infinite recursion when a subclass calls Run() from inside
59 // Cancel(). Only checked and modified on the target thread.
60 bool mCallingCancelWithinRun;
61
62 public:
63 NS_DECL_THREADSAFE_ISUPPORTS
64
65 // If you override Cancel() then you'll need to either call the base class
66 // Cancel() method or override IsCanceled() so that the Run() method bails out
67 // appropriately.
68 NS_DECL_NSICANCELABLERUNNABLE
69
70 // Passing a JSContext here is required for the WorkerThreadModifyBusyCount
71 // behavior. It also guarantees that any failure (false return) will throw an
72 // exception on the given context. If a context is not passed then failures
73 // must be dealt with by the caller.
74 bool
75 Dispatch(JSContext* aCx);
76
77 // See above note about Cancel().
78 virtual bool
79 IsCanceled() const
80 {
81 return mCanceled != 0;
82 }
83
84 static WorkerRunnable*
85 FromRunnable(nsIRunnable* aRunnable);
86
87 protected:
88 WorkerRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior)
89 #ifdef DEBUG
90 ;
91 #else
92 : mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0),
93 mCallingCancelWithinRun(false)
94 { }
95 #endif
96
97 // This class is reference counted.
98 virtual ~WorkerRunnable()
99 { }
100
101 // By default asserts that Dispatch() is being called on the right thread
102 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
103 // Also increments the busy count of |mWorkerPrivate| if targeting the
104 // WorkerThread.
105 virtual bool
106 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
107
108 // By default asserts that Dispatch() is being called on the right thread
109 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
110 // Also reports any Dispatch() failures as an exception on |aCx|, and
111 // busy count if targeting the WorkerThread and Dispatch() failed.
112 virtual void
113 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
114 bool aDispatchResult);
115
116 // Must be implemented by subclasses. Called on the target thread.
117 virtual bool
118 WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
119
120 // By default asserts that Run() (and WorkerRun()) were called on the correct
121 // thread. Any failures (false return from WorkerRun) are reported on |aCx|.
122 // Also sends an asynchronous message to the ParentThread if the busy
123 // count was previously modified in PreDispatch().
124 virtual void
125 PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
126
127 virtual bool
128 DispatchInternal();
129
130 // Calling Run() directly is not supported. Just call Dispatch() and
131 // WorkerRun() will be called on the correct thread automatically.
132 NS_DECL_NSIRUNNABLE
133 };
134
135 // This runnable is used to send a message directly to a worker's sync loop.
136 class WorkerSyncRunnable : public WorkerRunnable
137 {
138 protected:
139 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
140
141 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
142 // of a normal WorkerRunnable.
143 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
144 nsIEventTarget* aSyncLoopTarget);
145
146 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
147 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget);
148
149 virtual ~WorkerSyncRunnable();
150
151 private:
152 virtual bool
153 DispatchInternal() MOZ_OVERRIDE;
154 };
155
156 // This runnable is identical to WorkerSyncRunnable except it is meant to be
157 // used on the main thread only.
158 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable
159 {
160 protected:
161 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
162 // of a normal WorkerRunnable.
163 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
164 nsIEventTarget* aSyncLoopTarget)
165 : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget)
166 {
167 AssertIsOnMainThread();
168 }
169
170 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
171 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget)
172 : WorkerSyncRunnable(aWorkerPrivate, Move(aSyncLoopTarget))
173 {
174 AssertIsOnMainThread();
175 }
176
177 virtual ~MainThreadWorkerSyncRunnable()
178 { }
179
180 private:
181 virtual bool
182 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
183 {
184 AssertIsOnMainThread();
185 return true;
186 }
187
188 virtual void
189 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
190 bool aDispatchResult) MOZ_OVERRIDE;
191 };
192
193 // This runnable is used to stop a sync loop . As sync loops keep the busy count
194 // incremented as long as they run this runnable does not modify the busy count
195 // in any way.
196 class StopSyncLoopRunnable : public WorkerSyncRunnable
197 {
198 bool mResult;
199
200 public:
201 // Passing null for aSyncLoopTarget is not allowed.
202 StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
203 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget,
204 bool aResult);
205
206 // By default StopSyncLoopRunnables cannot be canceled since they could leave
207 // a sync loop spinning forever.
208 NS_DECL_NSICANCELABLERUNNABLE
209
210 protected:
211 virtual ~StopSyncLoopRunnable()
212 { }
213
214 // Called on the worker thread to set an exception on the context if mResult
215 // is false. Override if you need an exception.
216 virtual void
217 MaybeSetException(JSContext* aCx)
218 { }
219
220 private:
221 virtual bool
222 WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
223
224 virtual bool
225 DispatchInternal() MOZ_OVERRIDE;
226 };
227
228 // This runnable is identical to StopSyncLoopRunnable except it is meant to be
229 // used on the main thread only.
230 class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable
231 {
232 public:
233 // Passing null for aSyncLoopTarget is not allowed.
234 MainThreadStopSyncLoopRunnable(
235 WorkerPrivate* aWorkerPrivate,
236 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget,
237 bool aResult)
238 : StopSyncLoopRunnable(aWorkerPrivate, Move(aSyncLoopTarget), aResult)
239 {
240 AssertIsOnMainThread();
241 }
242
243 protected:
244 virtual ~MainThreadStopSyncLoopRunnable()
245 { }
246
247 private:
248 virtual bool
249 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
250 {
251 AssertIsOnMainThread();
252 return true;
253 }
254
255 virtual void
256 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
257 bool aDispatchResult) MOZ_OVERRIDE;
258 };
259
260 // This runnable is processed as soon as it is received by the worker,
261 // potentially running before previously queued runnables and perhaps even with
262 // other JS code executing on the stack. These runnables must not alter the
263 // state of the JS runtime and should only twiddle state values. The busy count
264 // is never modified.
265 class WorkerControlRunnable : public WorkerRunnable
266 {
267 friend class WorkerPrivate;
268
269 protected:
270 WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
271 TargetAndBusyBehavior aBehavior)
272 #ifdef DEBUG
273 ;
274 #else
275 : WorkerRunnable(aWorkerPrivate, aBehavior)
276 { }
277 #endif
278
279 virtual ~WorkerControlRunnable()
280 { }
281
282 public:
283 NS_DECL_ISUPPORTS_INHERITED
284
285 private:
286 virtual bool
287 DispatchInternal() MOZ_OVERRIDE;
288
289 // Should only be called by WorkerPrivate::DoRunLoop.
290 using WorkerRunnable::Cancel;
291 };
292
293 // A convenience class for WorkerControlRunnables that originate on the main
294 // thread.
295 class MainThreadWorkerControlRunnable : public WorkerControlRunnable
296 {
297 protected:
298 MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
299 : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
300 { }
301
302 virtual ~MainThreadWorkerControlRunnable()
303 { }
304
305 virtual bool
306 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
307 {
308 AssertIsOnMainThread();
309 return true;
310 }
311
312 virtual void
313 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
314 bool aDispatchResult) MOZ_OVERRIDE;
315 };
316
317 // A WorkerRunnable that should be dispatched from the worker to itself for
318 // async tasks. This will increment the busy count PostDispatch() (only if
319 // dispatch was successful) and decrement it in PostRun().
320 //
321 // Async tasks will almost always want to use this since
322 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
323 class WorkerSameThreadRunnable : public WorkerRunnable
324 {
325 protected:
326 WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
327 : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
328 { }
329
330 virtual ~WorkerSameThreadRunnable()
331 { }
332
333 virtual bool
334 PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
335
336 virtual void
337 PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
338 bool aDispatchResult) MOZ_OVERRIDE;
339
340 virtual void
341 PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
342 bool aRunResult) MOZ_OVERRIDE;
343 };
344
345 END_WORKERS_NAMESPACE
346
347 #endif // mozilla_dom_workers_workerrunnable_h__

mercurial