Bug 1835710 - Cancel off-thread JIT compilation before changing nursery allocation...
[gecko.git] / dom / workers / WorkerRunnable.h
blob9a7697e0d56c8b35aa344c6b8391edc451d09ef1
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 "nsIRunnable.h"
19 #include "nsISupports.h"
20 #include "nsStringFwd.h"
21 #include "nsThreadUtils.h"
22 #include "nscore.h"
24 struct JSContext;
25 class nsIEventTarget;
26 class nsIGlobalObject;
28 namespace mozilla {
30 class ErrorResult;
32 namespace dom {
34 class WorkerPrivate;
36 // Use this runnable to communicate from the worker to its parent or vice-versa.
37 // The busy count must be taken into consideration and declared at construction
38 // time.
39 class WorkerRunnable : public nsIRunnable {
40 public:
41 enum TargetAndBusyBehavior {
42 // Target the main thread for top-level workers, otherwise target the
43 // WorkerThread of the worker's parent. No change to the busy count.
44 ParentThreadUnchangedBusyCount,
46 // Target the thread where the worker event loop runs. The busy count will
47 // be incremented before dispatching and decremented (asynchronously) after
48 // running.
49 WorkerThreadModifyBusyCount,
51 // Target the thread where the worker event loop runs. The busy count will
52 // not be modified in any way. Besides worker-internal runnables this is
53 // almost always the wrong choice.
54 WorkerThreadUnchangedBusyCount
57 protected:
58 // The WorkerPrivate that this runnable is associated with.
59 WorkerPrivate* mWorkerPrivate;
61 // See above.
62 TargetAndBusyBehavior mBehavior;
64 private:
65 // Whether or not Cancel() is currently being called from inside the Run()
66 // method. Avoids infinite recursion when a subclass calls Run() from inside
67 // Cancel(). Only checked and modified on the target thread.
68 bool mCallingCancelWithinRun;
70 public:
71 NS_DECL_THREADSAFE_ISUPPORTS
73 virtual nsresult Cancel();
75 // The return value is true if and only if both PreDispatch and
76 // DispatchInternal return true.
77 bool Dispatch();
79 // True if this runnable is handled by running JavaScript in some global that
80 // could possibly be a debuggee, and thus needs to be deferred when the target
81 // is paused in the debugger, until the JavaScript invocation in progress has
82 // run to completion. Examples are MessageEventRunnable and
83 // ReportErrorRunnable. These runnables are segregated into separate
84 // ThrottledEventQueues, which the debugger pauses.
86 // Note that debugger runnables do not fall in this category, since we don't
87 // support debugging the debugger server at the moment.
88 virtual bool IsDebuggeeRunnable() const { return false; }
90 static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
92 protected:
93 WorkerRunnable(WorkerPrivate* aWorkerPrivate,
94 TargetAndBusyBehavior aBehavior = WorkerThreadModifyBusyCount)
95 #ifdef DEBUG
97 #else
98 : mWorkerPrivate(aWorkerPrivate),
99 mBehavior(aBehavior),
100 mCallingCancelWithinRun(false) {
102 #endif
104 // This class is reference counted.
105 virtual ~WorkerRunnable() = default;
107 // Returns true if this runnable should be dispatched to the debugger queue,
108 // and false otherwise.
109 virtual bool IsDebuggerRunnable() const;
111 nsIGlobalObject* DefaultGlobalObject() const;
113 // By default asserts that Dispatch() is being called on the right thread
114 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
115 // Also increments the busy count of |mWorkerPrivate| if targeting the
116 // WorkerThread.
117 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate);
119 // By default asserts that Dispatch() is being called on the right thread
120 // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
121 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
122 bool aDispatchResult);
124 // May be implemented by subclasses if desired if they need to do some sort of
125 // setup before we try to set up our JSContext and compartment for real.
126 // Typically the only thing that should go in here is creation of the worker's
127 // global.
129 // If false is returned, WorkerRun will not be called at all. PostRun will
130 // still be called, with false passed for aRunResult.
131 virtual bool PreRun(WorkerPrivate* aWorkerPrivate);
133 // Must be implemented by subclasses. Called on the target thread. The return
134 // value will be passed to PostRun(). The JSContext passed in here comes from
135 // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
136 // mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of
137 // mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
138 // unless that reflector is null, in which case it's in the compartment of the
139 // parent global (which is the compartment reflector would have been in), or
140 // in the null compartment if there is no parent global. For other mBehavior
141 // values, we're running on the worker thread and aCx is in whatever
142 // compartment GetCurrentWorkerThreadJSContext() was in when
143 // nsIRunnable::Run() got called. This is actually important for cases when a
144 // runnable spins a syncloop and wants everything that happens during the
145 // syncloop to happen in the compartment that runnable set up (which may, for
146 // example, be a debugger sandbox compartment!). If aCx wasn't in a
147 // compartment to start with, aCx will be in either the debugger global's
148 // compartment or the worker's global's compartment depending on whether
149 // IsDebuggerRunnable() is true.
151 // Immediately after WorkerRun returns, the caller will assert that either it
152 // returns false or there is no exception pending on aCx. Then it will report
153 // any pending exceptions on aCx.
154 virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
156 // By default asserts that Run() (and WorkerRun()) were called on the correct
157 // thread. Also sends an asynchronous message to the ParentThread if the
158 // busy count was previously modified in PreDispatch().
160 // The aCx passed here is the same one as was passed to WorkerRun and is
161 // still in the same compartment. PostRun implementations must NOT leave an
162 // exception on the JSContext and must not run script, because the incoming
163 // JSContext may be in the null compartment.
164 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
165 bool aRunResult);
167 virtual bool DispatchInternal();
169 // Calling Run() directly is not supported. Just call Dispatch() and
170 // WorkerRun() will be called on the correct thread automatically.
171 NS_DECL_NSIRUNNABLE
174 // This runnable is used to send a message to a worker debugger.
175 class WorkerDebuggerRunnable : public WorkerRunnable {
176 protected:
177 explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate)
178 : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
180 virtual ~WorkerDebuggerRunnable() = default;
182 private:
183 virtual bool IsDebuggerRunnable() const override { return true; }
185 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
186 AssertIsOnMainThread();
188 return true;
191 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
192 bool aDispatchResult) override;
195 // This runnable is used to send a message directly to a worker's sync loop.
196 class WorkerSyncRunnable : public WorkerRunnable {
197 protected:
198 nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
200 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
201 // of a normal WorkerRunnable.
202 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
203 nsIEventTarget* aSyncLoopTarget);
205 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
206 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget);
208 virtual ~WorkerSyncRunnable();
210 virtual bool DispatchInternal() override;
213 // This runnable is identical to WorkerSyncRunnable except it is meant to be
214 // created on and dispatched from the main thread only. Its WorkerRun/PostRun
215 // will run on the worker thread.
216 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
217 protected:
218 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
219 // of a normal WorkerRunnable.
220 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
221 nsIEventTarget* aSyncLoopTarget)
222 : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) {
223 AssertIsOnMainThread();
226 MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
227 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget)
228 : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget)) {
229 AssertIsOnMainThread();
232 virtual ~MainThreadWorkerSyncRunnable() = default;
234 private:
235 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
236 AssertIsOnMainThread();
237 return true;
240 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
241 bool aDispatchResult) override;
244 // This runnable is processed as soon as it is received by the worker,
245 // potentially running before previously queued runnables and perhaps even with
246 // other JS code executing on the stack. These runnables must not alter the
247 // state of the JS runtime and should only twiddle state values. The busy count
248 // is never modified.
249 class WorkerControlRunnable : public WorkerRunnable {
250 friend class WorkerPrivate;
252 protected:
253 WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
254 TargetAndBusyBehavior aBehavior)
255 #ifdef DEBUG
257 #else
258 : WorkerRunnable(aWorkerPrivate, aBehavior) {
260 #endif
262 virtual ~WorkerControlRunnable() = default;
264 nsresult Cancel() override;
266 public:
267 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, WorkerRunnable)
269 private:
270 virtual bool DispatchInternal() override;
272 // Should only be called by WorkerPrivate::DoRunLoop.
273 using WorkerRunnable::Cancel;
276 // A convenience class for WorkerRunnables that are originated on the main
277 // thread.
278 class MainThreadWorkerRunnable : public WorkerRunnable {
279 protected:
280 explicit MainThreadWorkerRunnable(WorkerPrivate* aWorkerPrivate)
281 : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {
282 AssertIsOnMainThread();
285 virtual ~MainThreadWorkerRunnable() = default;
287 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
288 AssertIsOnMainThread();
289 return true;
292 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
293 bool aDispatchResult) override {
294 AssertIsOnMainThread();
298 // A convenience class for WorkerControlRunnables that originate on the main
299 // thread.
300 class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
301 protected:
302 explicit MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
303 : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
305 virtual ~MainThreadWorkerControlRunnable() = default;
307 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
308 AssertIsOnMainThread();
309 return true;
312 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
313 bool aDispatchResult) override {
314 AssertIsOnMainThread();
318 // A WorkerRunnable that should be dispatched from the worker to itself for
319 // async tasks. This will increment the busy count PostDispatch() (only if
320 // dispatch was successful) and decrement it in PostRun().
322 // Async tasks will almost always want to use this since
323 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
324 class WorkerSameThreadRunnable : public WorkerRunnable {
325 protected:
326 explicit WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
327 : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) {}
329 virtual ~WorkerSameThreadRunnable() = default;
331 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
333 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
334 bool aDispatchResult) override;
336 // We just delegate PostRun to WorkerRunnable, since it does exactly
337 // what we want.
340 // Base class for the runnable objects, which makes a synchronous call to
341 // dispatch the tasks from the worker thread to the main thread.
343 // Note that the derived class must override MainThreadRun.
344 class WorkerMainThreadRunnable : public Runnable {
345 protected:
346 WorkerPrivate* mWorkerPrivate;
347 nsCOMPtr<nsISerialEventTarget> mSyncLoopTarget;
348 const nsCString mTelemetryKey;
350 explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
351 const nsACString& aTelemetryKey);
352 ~WorkerMainThreadRunnable();
354 virtual bool MainThreadRun() = 0;
356 public:
357 // Dispatch the runnable to the main thread. If dispatch to main thread
358 // fails, or if the worker is in a state equal or greater of aFailStatus, an
359 // error will be reported on aRv. Normally you want to use 'Canceling' for
360 // aFailStatus, except if you want an infallible runnable. In this case, use
361 // 'Killing'.
362 // In that case the error MUST be propagated out to script.
363 void Dispatch(WorkerStatus aFailStatus, ErrorResult& aRv);
365 private:
366 NS_IMETHOD Run() override;
369 // This runnable is an helper class for dispatching something from a worker
370 // thread to the main-thread and back to the worker-thread. During this
371 // operation, this class will keep the worker alive.
372 // The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name
373 // says, only to release resources, no JS has to be executed, no timers, or
374 // other things. The reason of such limitations is that, in order to execute
375 // this method in any condition (also when the worker is shutting down), a
376 // Control Runnable is used, and, this could generate a reordering of existing
377 // runnables.
378 class WorkerProxyToMainThreadRunnable : public Runnable {
379 protected:
380 WorkerProxyToMainThreadRunnable();
382 virtual ~WorkerProxyToMainThreadRunnable();
384 // First this method is called on the main-thread.
385 virtual void RunOnMainThread(WorkerPrivate* aWorkerPrivate) = 0;
387 // After this second method is called on the worker-thread.
388 virtual void RunBackOnWorkerThreadForCleanup(
389 WorkerPrivate* aWorkerPrivate) = 0;
391 public:
392 bool Dispatch(WorkerPrivate* aWorkerPrivate);
394 virtual bool ForMessaging() const { return false; }
396 private:
397 NS_IMETHOD Run() override;
399 void PostDispatchOnMainThread();
401 void ReleaseWorker();
403 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
406 // This runnable is used to stop a sync loop and it's meant to be used on the
407 // main-thread only. As sync loops keep the busy count incremented as long as
408 // they run this runnable does not modify the busy count
409 // in any way.
410 class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
411 nsresult mResult;
413 public:
414 // Passing null for aSyncLoopTarget is not allowed.
415 MainThreadStopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
416 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
417 nsresult aResult);
419 // By default StopSyncLoopRunnables cannot be canceled since they could leave
420 // a sync loop spinning forever.
421 nsresult Cancel() override;
423 protected:
424 virtual ~MainThreadStopSyncLoopRunnable() = default;
426 private:
427 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
428 AssertIsOnMainThread();
429 return true;
432 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
433 bool aDispatchResult) override;
435 virtual bool WorkerRun(JSContext* aCx,
436 WorkerPrivate* aWorkerPrivate) override;
438 bool DispatchInternal() final;
441 // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript
442 // error reports, and so on) must not be delivered while that content is in the
443 // midst of being debugged; the debuggee must be allowed to complete its current
444 // JavaScript invocation and return to its own event loop. Only then is it
445 // prepared for messages sent from the worker.
447 // Runnables that need to be deferred in this way should inherit from this
448 // class. They will be routed to mMainThreadDebuggeeEventTarget, which is paused
449 // while the window is suspended, as it is whenever the debugger spins its
450 // nested event loop. When the debugger leaves its nested event loop, it resumes
451 // the window, so that mMainThreadDebuggeeEventTarget will resume delivering
452 // runnables from the worker when control returns to the main event loop.
454 // When a page enters the bfcache, it freezes all its workers. Since a frozen
455 // worker processes only control runnables, it doesn't take any special
456 // consideration to prevent WorkerDebuggeeRunnables sent from child to parent
457 // workers from running; they'll never run anyway. But WorkerDebuggeeRunnables
458 // from a top-level frozen worker to its parent window must not be delivered
459 // either, even as the main thread event loop continues to spin. Thus, freezing
460 // a top-level worker also pauses mMainThreadDebuggeeEventTarget.
461 class WorkerDebuggeeRunnable : public WorkerRunnable {
462 protected:
463 WorkerDebuggeeRunnable(
464 WorkerPrivate* aWorkerPrivate,
465 TargetAndBusyBehavior aBehavior = ParentThreadUnchangedBusyCount)
466 : WorkerRunnable(aWorkerPrivate, aBehavior) {}
468 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
470 private:
471 // This override is deliberately private: it doesn't make sense to call it if
472 // we know statically that we are a WorkerDebuggeeRunnable.
473 bool IsDebuggeeRunnable() const override { return true; }
475 // Runnables sent upwards, to the content window or parent worker, must keep
476 // their sender alive until they are delivered: they check back with the
477 // sender in case it has been terminated after having dispatched the runnable
478 // (in which case it should not be acted upon); and runnables sent to content
479 // wait until delivery to determine the target window, since
480 // WorkerPrivate::GetWindow may only be used on the main thread.
482 // Runnables sent downwards, from content to a worker or from a worker to a
483 // child, keep the sender alive because they are WorkerThreadModifyBusyCount
484 // runnables, and so leave this null.
485 RefPtr<ThreadSafeWorkerRef> mSender;
488 } // namespace dom
489 } // namespace mozilla
491 #endif // mozilla_dom_workers_workerrunnable_h__