|
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__ |