Bug 1787199 [wpt PR 35620] - Add tests for `VisibilityStateEntry`, a=testonly
[gecko.git] / dom / workers / WorkerRunnable.h
blobf0ca9a278651e1771d56486c3c4a034efd62bc18
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 <cstdint>
11 #include <utility>
12 #include "MainThreadUtils.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/RefPtr.h"
15 #include "mozilla/dom/WorkerRef.h"
16 #include "mozilla/dom/WorkerStatus.h"
17 #include "nsCOMPtr.h"
18 #include "nsICancelableRunnable.h"
19 #include "nsIRunnable.h"
20 #include "nsISupports.h"
21 #include "nsStringFwd.h"
22 #include "nsThreadUtils.h"
23 #include "nscore.h"
25 struct JSContext;
26 class nsIEventTarget;
27 class nsIGlobalObject;
29 namespace mozilla {
31 class ErrorResult;
33 namespace dom {
35 class WorkerPrivate;
37 // Use this runnable to communicate from the worker to its parent or vice-versa.
38 // The busy count must be taken into consideration and declared at construction
39 // time.
40 class WorkerRunnable : public nsIRunnable, public nsICancelableRunnable {
41 public:
42 enum TargetAndBusyBehavior {
43 // Target the main thread for top-level workers, otherwise target the
44 // WorkerThread of the worker's parent. No change to the busy count.
45 ParentThreadUnchangedBusyCount,
47 // Target the thread where the worker event loop runs. The busy count will
48 // be incremented before dispatching and decremented (asynchronously) after
49 // running.
50 WorkerThreadModifyBusyCount,
52 // Target the thread where the worker event loop runs. The busy count will
53 // not be modified in any way. Besides worker-internal runnables this is
54 // almost always the wrong choice.
55 WorkerThreadUnchangedBusyCount
58 protected:
59 // The WorkerPrivate that this runnable is associated with.
60 WorkerPrivate* mWorkerPrivate;
62 // See above.
63 TargetAndBusyBehavior mBehavior;
65 // It's unclear whether or not Cancel() is supposed to work when called on any
66 // thread. To be safe we're using an atomic but it's likely overkill.
67 Atomic<uint32_t> mCanceled;
69 private:
70 // Whether or not Cancel() is currently being called from inside the Run()
71 // method. Avoids infinite recursion when a subclass calls Run() from inside
72 // Cancel(). Only checked and modified on the target thread.
73 bool mCallingCancelWithinRun;
75 public:
76 NS_DECL_THREADSAFE_ISUPPORTS
78 // If you override Cancel() then you'll need to either call the base class
79 // Cancel() method or override IsCanceled() so that the Run() method bails out
80 // appropriately.
81 // Cancel() should not be called more than once and we throw
82 // NS_ERROR_UNEXPECTED if it is. If you override it, ensure to call the base
83 // class method first and bail out on failure to avoid unexpected side
84 // effects.
85 nsresult Cancel() override;
87 // The return value is true if and only if both PreDispatch and
88 // DispatchInternal return true.
89 bool Dispatch();
91 // See above note about Cancel().
92 // TODO: Check if we can remove the possibility to override IsCanceled.
93 virtual bool IsCanceled() const { return mCanceled != 0; }
95 // True if this runnable is handled by running JavaScript in some global that
96 // could possibly be a debuggee, and thus needs to be deferred when the target
97 // is paused in the debugger, until the JavaScript invocation in progress has
98 // run to completion. Examples are MessageEventRunnable and
99 // ReportErrorRunnable. These runnables are segregated into separate
100 // ThrottledEventQueues, which the debugger pauses.
102 // Note that debugger runnables do not fall in this category, since we don't
103 // support debugging the debugger server at the moment.
104 virtual bool IsDebuggeeRunnable() const { return false; }
106 static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
108 protected:
109 WorkerRunnable(WorkerPrivate* aWorkerPrivate,
110 TargetAndBusyBehavior aBehavior = WorkerThreadModifyBusyCount)
111 #ifdef DEBUG
113 #else
114 : mWorkerPrivate(aWorkerPrivate),
115 mBehavior(aBehavior),
116 mCanceled(0),
117 mCallingCancelWithinRun(false) {
119 #endif
121 // This class is reference counted.
122 virtual ~WorkerRunnable() = default;
124 // Returns true if this runnable should be dispatched to the debugger queue,
125 // and false otherwise.
126 virtual bool IsDebuggerRunnable() const;
128 nsIGlobalObject* DefaultGlobalObject() const;
130 // By default asserts that Dispatch() is being called on the right thread
131 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
132 // Also increments the busy count of |mWorkerPrivate| if targeting the
133 // WorkerThread.
134 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate);
136 // By default asserts that Dispatch() is being called on the right thread
137 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
138 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
139 bool aDispatchResult);
141 // May be implemented by subclasses if desired if they need to do some sort of
142 // setup before we try to set up our JSContext and compartment for real.
143 // Typically the only thing that should go in here is creation of the worker's
144 // global.
146 // If false is returned, WorkerRun will not be called at all. PostRun will
147 // still be called, with false passed for aRunResult.
148 virtual bool PreRun(WorkerPrivate* aWorkerPrivate);
150 // Must be implemented by subclasses. Called on the target thread. The return
151 // value will be passed to PostRun(). The JSContext passed in here comes from
152 // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
153 // mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of
154 // mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
155 // unless that reflector is null, in which case it's in the compartment of the
156 // parent global (which is the compartment reflector would have been in), or
157 // in the null compartment if there is no parent global. For other mBehavior
158 // values, we're running on the worker thread and aCx is in whatever
159 // compartment GetCurrentWorkerThreadJSContext() was in when
160 // nsIRunnable::Run() got called. This is actually important for cases when a
161 // runnable spins a syncloop and wants everything that happens during the
162 // syncloop to happen in the compartment that runnable set up (which may, for
163 // example, be a debugger sandbox compartment!). If aCx wasn't in a
164 // compartment to start with, aCx will be in either the debugger global's
165 // compartment or the worker's global's compartment depending on whether
166 // IsDebuggerRunnable() is true.
168 // Immediately after WorkerRun returns, the caller will assert that either it
169 // returns false or there is no exception pending on aCx. Then it will report
170 // any pending exceptions on aCx.
171 virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
173 // By default asserts that Run() (and WorkerRun()) were called on the correct
174 // thread. Also sends an asynchronous message to the ParentThread if the
175 // busy count was previously modified in PreDispatch().
177 // The aCx passed here is the same one as was passed to WorkerRun and is
178 // still in the same compartment. PostRun implementations must NOT leave an
179 // exception on the JSContext and must not run script, because the incoming
180 // JSContext may be in the null compartment.
181 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
182 bool aRunResult);
184 virtual bool DispatchInternal();
186 // Calling Run() directly is not supported. Just call Dispatch() and
187 // WorkerRun() will be called on the correct thread automatically.
188 NS_DECL_NSIRUNNABLE
191 // This runnable is used to send a message to a worker debugger.
192 class WorkerDebuggerRunnable : public WorkerRunnable {
193 protected:
194 explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate)
195 : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
197 virtual ~WorkerDebuggerRunnable() = default;
199 private:
200 virtual bool IsDebuggerRunnable() const override { return true; }
202 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
203 AssertIsOnMainThread();
205 return true;
208 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
209 bool aDispatchResult) override;
212 // This runnable is used to send a message directly to a worker's sync loop.
213 class WorkerSyncRunnable : public WorkerRunnable {
214 protected:
215 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
217 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
218 // of a normal WorkerRunnable.
219 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
220 nsIEventTarget* aSyncLoopTarget);
222 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
223 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget);
225 virtual ~WorkerSyncRunnable();
227 virtual bool DispatchInternal() override;
230 // This runnable is identical to WorkerSyncRunnable except it is meant to be
231 // created on and dispatched from the main thread only. Its WorkerRun/PostRun
232 // will run on the worker thread.
233 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
234 protected:
235 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
236 // of a normal WorkerRunnable.
237 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
238 nsIEventTarget* aSyncLoopTarget)
239 : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) {
240 AssertIsOnMainThread();
243 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
244 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget)
245 : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget)) {
246 AssertIsOnMainThread();
249 virtual ~MainThreadWorkerSyncRunnable() = default;
251 private:
252 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
253 AssertIsOnMainThread();
254 return true;
257 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
258 bool aDispatchResult) override;
261 // This runnable is processed as soon as it is received by the worker,
262 // potentially running before previously queued runnables and perhaps even with
263 // other JS code executing on the stack. These runnables must not alter the
264 // state of the JS runtime and should only twiddle state values. The busy count
265 // is never modified.
266 class WorkerControlRunnable : public WorkerRunnable {
267 friend class WorkerPrivate;
269 protected:
270 WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
271 TargetAndBusyBehavior aBehavior)
272 #ifdef DEBUG
274 #else
275 : WorkerRunnable(aWorkerPrivate, aBehavior) {
277 #endif
279 virtual ~WorkerControlRunnable() = default;
281 nsresult Cancel() override;
283 public:
284 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, WorkerRunnable)
286 private:
287 virtual bool DispatchInternal() override;
289 // Should only be called by WorkerPrivate::DoRunLoop.
290 using WorkerRunnable::Cancel;
293 // A convenience class for WorkerRunnables that are originated on the main
294 // thread.
295 class MainThreadWorkerRunnable : public WorkerRunnable {
296 protected:
297 explicit MainThreadWorkerRunnable(WorkerPrivate* aWorkerPrivate)
298 : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {
299 AssertIsOnMainThread();
302 virtual ~MainThreadWorkerRunnable() = default;
304 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
305 AssertIsOnMainThread();
306 return true;
309 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
310 bool aDispatchResult) override {
311 AssertIsOnMainThread();
315 // A convenience class for WorkerControlRunnables that originate on the main
316 // thread.
317 class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
318 protected:
319 explicit MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
320 : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
322 virtual ~MainThreadWorkerControlRunnable() = default;
324 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
325 AssertIsOnMainThread();
326 return true;
329 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
330 bool aDispatchResult) override {
331 AssertIsOnMainThread();
335 // A WorkerRunnable that should be dispatched from the worker to itself for
336 // async tasks. This will increment the busy count PostDispatch() (only if
337 // dispatch was successful) and decrement it in PostRun().
339 // Async tasks will almost always want to use this since
340 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
341 class WorkerSameThreadRunnable : public WorkerRunnable {
342 protected:
343 explicit WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
344 : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) {}
346 virtual ~WorkerSameThreadRunnable() = default;
348 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
350 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
351 bool aDispatchResult) override;
353 // We just delegate PostRun to WorkerRunnable, since it does exactly
354 // what we want.
357 // Base class for the runnable objects, which makes a synchronous call to
358 // dispatch the tasks from the worker thread to the main thread.
360 // Note that the derived class must override MainThreadRun.
361 class WorkerMainThreadRunnable : public Runnable {
362 protected:
363 WorkerPrivate* mWorkerPrivate;
364 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
365 const nsCString mTelemetryKey;
367 explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
368 const nsACString& aTelemetryKey);
369 ~WorkerMainThreadRunnable();
371 virtual bool MainThreadRun() = 0;
373 public:
374 // Dispatch the runnable to the main thread. If dispatch to main thread
375 // fails, or if the worker is in a state equal or greater of aFailStatus, an
376 // error will be reported on aRv. Normally you want to use 'Canceling' for
377 // aFailStatus, except if you want an infallible runnable. In this case, use
378 // 'Killing'.
379 // In that case the error MUST be propagated out to script.
380 void Dispatch(WorkerStatus aFailStatus, ErrorResult& aRv);
382 private:
383 NS_IMETHOD Run() override;
386 // This runnable is an helper class for dispatching something from a worker
387 // thread to the main-thread and back to the worker-thread. During this
388 // operation, this class will keep the worker alive.
389 // The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name
390 // says, only to release resources, no JS has to be executed, no timers, or
391 // other things. The reason of such limitations is that, in order to execute
392 // this method in any condition (also when the worker is shutting down), a
393 // Control Runnable is used, and, this could generate a reordering of existing
394 // runnables.
395 class WorkerProxyToMainThreadRunnable : public Runnable {
396 protected:
397 WorkerProxyToMainThreadRunnable();
399 virtual ~WorkerProxyToMainThreadRunnable();
401 // First this method is called on the main-thread.
402 virtual void RunOnMainThread(WorkerPrivate* aWorkerPrivate) = 0;
404 // After this second method is called on the worker-thread.
405 virtual void RunBackOnWorkerThreadForCleanup(
406 WorkerPrivate* aWorkerPrivate) = 0;
408 public:
409 bool Dispatch(WorkerPrivate* aWorkerPrivate);
411 virtual bool ForMessaging() const { return false; }
413 private:
414 NS_IMETHOD Run() override;
416 void PostDispatchOnMainThread();
418 void ReleaseWorker();
420 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
423 // This runnable is used to stop a sync loop and it's meant to be used on the
424 // main-thread only. As sync loops keep the busy count incremented as long as
425 // they run this runnable does not modify the busy count
426 // in any way.
427 class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
428 bool mResult;
430 public:
431 // Passing null for aSyncLoopTarget is not allowed.
432 MainThreadStopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
433 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
434 bool aResult);
436 // By default StopSyncLoopRunnables cannot be canceled since they could leave
437 // a sync loop spinning forever.
438 nsresult Cancel() override;
440 protected:
441 virtual ~MainThreadStopSyncLoopRunnable() = default;
443 private:
444 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
445 AssertIsOnMainThread();
446 return true;
449 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
450 bool aDispatchResult) override;
452 virtual bool WorkerRun(JSContext* aCx,
453 WorkerPrivate* aWorkerPrivate) override;
455 bool DispatchInternal() final;
458 // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript
459 // error reports, and so on) must not be delivered while that content is in the
460 // midst of being debugged; the debuggee must be allowed to complete its current
461 // JavaScript invocation and return to its own event loop. Only then is it
462 // prepared for messages sent from the worker.
464 // Runnables that need to be deferred in this way should inherit from this
465 // class. They will be routed to mMainThreadDebuggeeEventTarget, which is paused
466 // while the window is suspended, as it is whenever the debugger spins its
467 // nested event loop. When the debugger leaves its nested event loop, it resumes
468 // the window, so that mMainThreadDebuggeeEventTarget will resume delivering
469 // runnables from the worker when control returns to the main event loop.
471 // When a page enters the bfcache, it freezes all its workers. Since a frozen
472 // worker processes only control runnables, it doesn't take any special
473 // consideration to prevent WorkerDebuggeeRunnables sent from child to parent
474 // workers from running; they'll never run anyway. But WorkerDebuggeeRunnables
475 // from a top-level frozen worker to its parent window must not be delivered
476 // either, even as the main thread event loop continues to spin. Thus, freezing
477 // a top-level worker also pauses mMainThreadDebuggeeEventTarget.
478 class WorkerDebuggeeRunnable : public WorkerRunnable {
479 protected:
480 WorkerDebuggeeRunnable(
481 WorkerPrivate* aWorkerPrivate,
482 TargetAndBusyBehavior aBehavior = ParentThreadUnchangedBusyCount)
483 : WorkerRunnable(aWorkerPrivate, aBehavior) {}
485 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
487 private:
488 // This override is deliberately private: it doesn't make sense to call it if
489 // we know statically that we are a WorkerDebuggeeRunnable.
490 bool IsDebuggeeRunnable() const override { return true; }
492 // Runnables sent upwards, to the content window or parent worker, must keep
493 // their sender alive until they are delivered: they check back with the
494 // sender in case it has been terminated after having dispatched the runnable
495 // (in which case it should not be acted upon); and runnables sent to content
496 // wait until delivery to determine the target window, since
497 // WorkerPrivate::GetWindow may only be used on the main thread.
499 // Runnables sent downwards, from content to a worker or from a worker to a
500 // child, keep the sender alive because they are WorkerThreadModifyBusyCount
501 // runnables, and so leave this null.
502 RefPtr<ThreadSafeWorkerRef> mSender;
505 } // namespace dom
506 } // namespace mozilla
508 #endif // mozilla_dom_workers_workerrunnable_h__