Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / workers / WorkerRunnable.h
blob786b8c6d24820b9428d7c7a6acc4a5374231e2d8
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_workers_workerrunnable_h__
8 #define mozilla_dom_workers_workerrunnable_h__
10 #include "mozilla/dom/WorkerCommon.h"
11 #include "mozilla/dom/WorkerRef.h"
13 #include "nsICancelableRunnable.h"
15 #include "mozilla/Atomics.h"
16 #include "nsISupportsImpl.h"
17 #include "nsThreadUtils.h" /* nsRunnable */
19 struct JSContext;
20 class nsIEventTarget;
22 namespace mozilla {
24 class ErrorResult;
26 namespace dom {
28 class WorkerPrivate;
30 // Use this runnable to communicate from the worker to its parent or vice-versa.
31 // The busy count must be taken into consideration and declared at construction
32 // time.
33 class WorkerRunnable : public nsIRunnable, public nsICancelableRunnable {
34 public:
35 enum TargetAndBusyBehavior {
36 // Target the main thread for top-level workers, otherwise target the
37 // WorkerThread of the worker's parent. No change to the busy count.
38 ParentThreadUnchangedBusyCount,
40 // Target the thread where the worker event loop runs. The busy count will
41 // be incremented before dispatching and decremented (asynchronously) after
42 // running.
43 WorkerThreadModifyBusyCount,
45 // Target the thread where the worker event loop runs. The busy count will
46 // not be modified in any way. Besides worker-internal runnables this is
47 // almost always the wrong choice.
48 WorkerThreadUnchangedBusyCount
51 protected:
52 // The WorkerPrivate that this runnable is associated with.
53 WorkerPrivate* mWorkerPrivate;
55 // See above.
56 TargetAndBusyBehavior mBehavior;
58 // It's unclear whether or not Cancel() is supposed to work when called on any
59 // thread. To be safe we're using an atomic but it's likely overkill.
60 Atomic<uint32_t> mCanceled;
62 private:
63 // Whether or not Cancel() is currently being called from inside the Run()
64 // method. Avoids infinite recursion when a subclass calls Run() from inside
65 // Cancel(). Only checked and modified on the target thread.
66 bool mCallingCancelWithinRun;
68 public:
69 NS_DECL_THREADSAFE_ISUPPORTS
71 // If you override Cancel() then you'll need to either call the base class
72 // Cancel() method or override IsCanceled() so that the Run() method bails out
73 // appropriately.
74 nsresult Cancel() override;
76 // The return value is true if and only if both PreDispatch and
77 // DispatchInternal return true.
78 bool Dispatch();
80 // See above note about Cancel().
81 virtual bool IsCanceled() const { return mCanceled != 0; }
83 // True if this runnable is handled by running JavaScript in some global that
84 // could possibly be a debuggee, and thus needs to be deferred when the target
85 // is paused in the debugger, until the JavaScript invocation in progress has
86 // run to completion. Examples are MessageEventRunnable and
87 // ReportErrorRunnable. These runnables are segregated into separate
88 // ThrottledEventQueues, which the debugger pauses.
90 // Note that debugger runnables do not fall in this category, since we don't
91 // support debugging the debugger server at the moment.
92 virtual bool IsDebuggeeRunnable() const { return false; }
94 static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
96 protected:
97 WorkerRunnable(WorkerPrivate* aWorkerPrivate,
98 TargetAndBusyBehavior aBehavior = WorkerThreadModifyBusyCount)
99 #ifdef DEBUG
101 #else
102 : mWorkerPrivate(aWorkerPrivate),
103 mBehavior(aBehavior),
104 mCanceled(0),
105 mCallingCancelWithinRun(false) {
107 #endif
109 // This class is reference counted.
110 virtual ~WorkerRunnable() {}
112 // Returns true if this runnable should be dispatched to the debugger queue,
113 // and false otherwise.
114 virtual bool IsDebuggerRunnable() const;
116 nsIGlobalObject* DefaultGlobalObject() const;
118 // By default asserts that Dispatch() is being called on the right thread
119 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
120 // Also increments the busy count of |mWorkerPrivate| if targeting the
121 // WorkerThread.
122 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate);
124 // By default asserts that Dispatch() is being called on the right thread
125 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
126 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
127 bool aDispatchResult);
129 // May be implemented by subclasses if desired if they need to do some sort of
130 // setup before we try to set up our JSContext and compartment for real.
131 // Typically the only thing that should go in here is creation of the worker's
132 // global.
134 // If false is returned, WorkerRun will not be called at all. PostRun will
135 // still be called, with false passed for aRunResult.
136 virtual bool PreRun(WorkerPrivate* aWorkerPrivate);
138 // Must be implemented by subclasses. Called on the target thread. The return
139 // value will be passed to PostRun(). The JSContext passed in here comes from
140 // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
141 // mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of
142 // mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
143 // unless that reflector is null, in which case it's in the compartment of the
144 // parent global (which is the compartment reflector would have been in), or
145 // in the null compartment if there is no parent global. For other mBehavior
146 // values, we're running on the worker thread and aCx is in whatever
147 // compartment GetCurrentWorkerThreadJSContext() was in when
148 // nsIRunnable::Run() got called. This is actually important for cases when a
149 // runnable spins a syncloop and wants everything that happens during the
150 // syncloop to happen in the compartment that runnable set up (which may, for
151 // example, be a debugger sandbox compartment!). If aCx wasn't in a
152 // compartment to start with, aCx will be in either the debugger global's
153 // compartment or the worker's global's compartment depending on whether
154 // IsDebuggerRunnable() is true.
156 // Immediately after WorkerRun returns, the caller will assert that either it
157 // returns false or there is no exception pending on aCx. Then it will report
158 // any pending exceptions on aCx.
159 virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
161 // By default asserts that Run() (and WorkerRun()) were called on the correct
162 // thread. Also sends an asynchronous message to the ParentThread if the
163 // busy count was previously modified in PreDispatch().
165 // The aCx passed here is the same one as was passed to WorkerRun and is
166 // still in the same compartment. PostRun implementations must NOT leave an
167 // exception on the JSContext and must not run script, because the incoming
168 // JSContext may be in the null compartment.
169 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
170 bool aRunResult);
172 virtual bool DispatchInternal();
174 // Calling Run() directly is not supported. Just call Dispatch() and
175 // WorkerRun() will be called on the correct thread automatically.
176 NS_DECL_NSIRUNNABLE
179 // This runnable is used to send a message to a worker debugger.
180 class WorkerDebuggerRunnable : public WorkerRunnable {
181 protected:
182 explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate)
183 : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
185 virtual ~WorkerDebuggerRunnable() {}
187 private:
188 virtual bool IsDebuggerRunnable() const override { return true; }
190 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
191 AssertIsOnMainThread();
193 return true;
196 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
197 bool aDispatchResult) override;
200 // This runnable is used to send a message directly to a worker's sync loop.
201 class WorkerSyncRunnable : public WorkerRunnable {
202 protected:
203 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
205 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
206 // of a normal WorkerRunnable.
207 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
208 nsIEventTarget* aSyncLoopTarget);
210 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
211 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget);
213 virtual ~WorkerSyncRunnable();
215 virtual bool DispatchInternal() override;
218 // This runnable is identical to WorkerSyncRunnable except it is meant to be
219 // created on and dispatched from the main thread only. Its WorkerRun/PostRun
220 // will run on the worker thread.
221 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
222 protected:
223 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
224 // of a normal WorkerRunnable.
225 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
226 nsIEventTarget* aSyncLoopTarget)
227 : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) {
228 AssertIsOnMainThread();
231 MainThreadWorkerSyncRunnable(
232 WorkerPrivate* aWorkerPrivate,
233 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget)
234 : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget)) {
235 AssertIsOnMainThread();
238 virtual ~MainThreadWorkerSyncRunnable() {}
240 private:
241 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
242 AssertIsOnMainThread();
243 return true;
246 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
247 bool aDispatchResult) override;
250 // This runnable is processed as soon as it is received by the worker,
251 // potentially running before previously queued runnables and perhaps even with
252 // other JS code executing on the stack. These runnables must not alter the
253 // state of the JS runtime and should only twiddle state values. The busy count
254 // is never modified.
255 class WorkerControlRunnable : public WorkerRunnable {
256 friend class WorkerPrivate;
258 protected:
259 WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
260 TargetAndBusyBehavior aBehavior)
261 #ifdef DEBUG
263 #else
264 : WorkerRunnable(aWorkerPrivate, aBehavior) {
266 #endif
268 virtual ~WorkerControlRunnable() {}
270 nsresult Cancel() override;
272 public:
273 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, WorkerRunnable)
275 private:
276 virtual bool DispatchInternal() override;
278 // Should only be called by WorkerPrivate::DoRunLoop.
279 using WorkerRunnable::Cancel;
282 // A convenience class for WorkerRunnables that are originated on the main
283 // thread.
284 class MainThreadWorkerRunnable : public WorkerRunnable {
285 protected:
286 explicit MainThreadWorkerRunnable(WorkerPrivate* aWorkerPrivate)
287 : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {
288 AssertIsOnMainThread();
291 virtual ~MainThreadWorkerRunnable() {}
293 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
294 AssertIsOnMainThread();
295 return true;
298 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
299 bool aDispatchResult) override {
300 AssertIsOnMainThread();
304 // A convenience class for WorkerControlRunnables that originate on the main
305 // thread.
306 class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
307 protected:
308 explicit MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
309 : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
311 virtual ~MainThreadWorkerControlRunnable() {}
313 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
314 AssertIsOnMainThread();
315 return true;
318 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
319 bool aDispatchResult) override {
320 AssertIsOnMainThread();
324 // A WorkerRunnable that should be dispatched from the worker to itself for
325 // async tasks. This will increment the busy count PostDispatch() (only if
326 // dispatch was successful) and decrement it in PostRun().
328 // Async tasks will almost always want to use this since
329 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
330 class WorkerSameThreadRunnable : public WorkerRunnable {
331 protected:
332 explicit WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
333 : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) {}
335 virtual ~WorkerSameThreadRunnable() {}
337 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
339 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
340 bool aDispatchResult) override;
342 // We just delegate PostRun to WorkerRunnable, since it does exactly
343 // what we want.
346 // Base class for the runnable objects, which makes a synchronous call to
347 // dispatch the tasks from the worker thread to the main thread.
349 // Note that the derived class must override MainThreadRun.
350 class WorkerMainThreadRunnable : public Runnable {
351 protected:
352 WorkerPrivate* mWorkerPrivate;
353 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
354 const nsCString mTelemetryKey;
356 explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
357 const nsACString& aTelemetryKey);
358 ~WorkerMainThreadRunnable() {}
360 virtual bool MainThreadRun() = 0;
362 public:
363 // Dispatch the runnable to the main thread. If dispatch to main thread
364 // fails, or if the worker is in a state equal or greater of aFailStatus, an
365 // error will be reported on aRv. Normally you want to use 'Canceling' for
366 // aFailStatus, except if you want an infallible runnable. In this case, use
367 // 'Killing'.
368 // In that case the error MUST be propagated out to script.
369 void Dispatch(WorkerStatus aFailStatus, ErrorResult& aRv);
371 private:
372 NS_IMETHOD Run() override;
375 // This runnable is an helper class for dispatching something from a worker
376 // thread to the main-thread and back to the worker-thread. During this
377 // operation, this class will keep the worker alive.
378 // The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name
379 // says, only to release resources, no JS has to be executed, no timers, or
380 // other things. The reason of such limitations is that, in order to execute
381 // this method in any condition (also when the worker is shutting down), a
382 // Control Runnable is used, and, this could generate a reordering of existing
383 // runnables.
384 class WorkerProxyToMainThreadRunnable : public Runnable {
385 protected:
386 WorkerProxyToMainThreadRunnable();
388 virtual ~WorkerProxyToMainThreadRunnable();
390 // First this method is called on the main-thread.
391 virtual void RunOnMainThread(WorkerPrivate* aWorkerPrivate) = 0;
393 // After this second method is called on the worker-thread.
394 virtual void RunBackOnWorkerThreadForCleanup(
395 WorkerPrivate* aWorkerPrivate) = 0;
397 public:
398 bool Dispatch(WorkerPrivate* aWorkerPrivate);
400 virtual bool ForMessaging() const { return false; }
402 private:
403 NS_IMETHOD Run() override;
405 void PostDispatchOnMainThread();
407 void ReleaseWorker();
409 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
412 // This runnable is used to stop a sync loop and it's meant to be used on the
413 // main-thread only. As sync loops keep the busy count incremented as long as
414 // they run this runnable does not modify the busy count
415 // in any way.
416 class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
417 bool mResult;
419 public:
420 // Passing null for aSyncLoopTarget is not allowed.
421 MainThreadStopSyncLoopRunnable(
422 WorkerPrivate* aWorkerPrivate,
423 already_AddRefed<nsIEventTarget>&& aSyncLoopTarget, bool aResult);
425 // By default StopSyncLoopRunnables cannot be canceled since they could leave
426 // a sync loop spinning forever.
427 nsresult Cancel() override;
429 protected:
430 virtual ~MainThreadStopSyncLoopRunnable() {}
432 private:
433 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
434 AssertIsOnMainThread();
435 return true;
438 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
439 bool aDispatchResult) override;
441 virtual bool WorkerRun(JSContext* aCx,
442 WorkerPrivate* aWorkerPrivate) override;
444 bool DispatchInternal() final;
447 // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript
448 // error reports, and so on) must not be delivered while that content is in the
449 // midst of being debugged; the debuggee must be allowed to complete its current
450 // JavaScript invocation and return to its own event loop. Only then is it
451 // prepared for messages sent from the worker.
453 // Runnables that need to be deferred in this way should inherit from this
454 // class. They will be routed to mMainThreadDebuggeeEventTarget, which is paused
455 // while the window is suspended, as it is whenever the debugger spins its
456 // nested event loop. When the debugger leaves its nested event loop, it resumes
457 // the window, so that mMainThreadDebuggeeEventTarget will resume delivering
458 // runnables from the worker when control returns to the main event loop.
460 // When a page enters the bfcache, it freezes all its workers. Since a frozen
461 // worker processes only control runnables, it doesn't take any special
462 // consideration to prevent WorkerDebuggeeRunnables sent from child to parent
463 // workers from running; they'll never run anyway. But WorkerDebuggeeRunnables
464 // from a top-level frozen worker to its parent window must not be delivered
465 // either, even as the main thread event loop continues to spin. Thus, freezing
466 // a top-level worker also pauses mMainThreadDebuggeeEventTarget.
467 class WorkerDebuggeeRunnable : public WorkerRunnable {
468 protected:
469 WorkerDebuggeeRunnable(
470 WorkerPrivate* aWorkerPrivate,
471 TargetAndBusyBehavior aBehavior = ParentThreadUnchangedBusyCount)
472 : WorkerRunnable(aWorkerPrivate, aBehavior) {}
474 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
476 private:
477 // This override is deliberately private: it doesn't make sense to call it if
478 // we know statically that we are a WorkerDebuggeeRunnable.
479 bool IsDebuggeeRunnable() const override { return true; }
481 // Runnables sent upwards, to the content window or parent worker, must keep
482 // their sender alive until they are delivered: they check back with the
483 // sender in case it has been terminated after having dispatched the runnable
484 // (in which case it should not be acted upon); and runnables sent to content
485 // wait until delivery to determine the target window, since
486 // WorkerPrivate::GetWindow may only be used on the main thread.
488 // Runnables sent downwards, from content to a worker or from a worker to a
489 // child, keep the sender alive because they are WorkerThreadModifyBusyCount
490 // runnables, and so leave this null.
491 RefPtr<ThreadSafeWorkerRef> mSender;
494 } // namespace dom
495 } // namespace mozilla
497 #endif // mozilla_dom_workers_workerrunnable_h__