Bug 1867190 - Initialise the PHC allocate delay later r=glandium
[gecko.git] / dom / workers / WorkerRunnable.h
blob041694cfc2d1c96cbdff2fc6e32013ef4196e632
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 class WorkerRunnable : public nsIRunnable
38 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
40 public nsINamed
41 #endif
43 public:
44 enum Target {
45 // Target the main thread for top-level workers, otherwise target the
46 // WorkerThread of the worker's parent.
47 ParentThread,
49 // Target the thread where the worker event loop runs.
50 WorkerThread,
53 protected:
54 // The WorkerPrivate that this runnable is associated with.
55 WorkerPrivate* mWorkerPrivate;
57 // See above.
58 Target mTarget;
60 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
61 const char* mName = nullptr;
62 #endif
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
72 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
73 NS_DECL_NSINAMED
74 #endif
76 virtual nsresult Cancel();
78 // The return value is true if and only if both PreDispatch and
79 // DispatchInternal return true.
80 bool Dispatch();
82 // True if this runnable is handled by running JavaScript in some global that
83 // could possibly be a debuggee, and thus needs to be deferred when the target
84 // is paused in the debugger, until the JavaScript invocation in progress has
85 // run to completion. Examples are MessageEventRunnable and
86 // ReportErrorRunnable. These runnables are segregated into separate
87 // ThrottledEventQueues, which the debugger pauses.
89 // Note that debugger runnables do not fall in this category, since we don't
90 // support debugging the debugger server at the moment.
91 virtual bool IsDebuggeeRunnable() const { return false; }
93 static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
95 protected:
96 WorkerRunnable(WorkerPrivate* aWorkerPrivate,
97 const char* aName = "WorkerRunnable",
98 Target aTarget = WorkerThread)
99 #ifdef DEBUG
101 #else
102 : mWorkerPrivate(aWorkerPrivate),
103 mTarget(aTarget),
104 # ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
105 mName(aName),
106 # endif
107 mCallingCancelWithinRun(false) {
109 #endif
111 // This class is reference counted.
112 virtual ~WorkerRunnable() = default;
114 // Returns true if this runnable should be dispatched to the debugger queue,
115 // and false otherwise.
116 virtual bool IsDebuggerRunnable() const;
118 nsIGlobalObject* DefaultGlobalObject() const;
120 // By default asserts that Dispatch() is being called on the right thread
121 // (ParentThread if |mTarget| is 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).
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 // mTarget is ParentThread, 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 mTarget
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.
164 // The aCx passed here is the same one as was passed to WorkerRun and is
165 // still in the same compartment. PostRun implementations must NOT leave an
166 // exception on the JSContext and must not run script, because the incoming
167 // JSContext may be in the null compartment.
168 virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
169 bool aRunResult);
171 virtual bool DispatchInternal();
173 // Calling Run() directly is not supported. Just call Dispatch() and
174 // WorkerRun() will be called on the correct thread automatically.
175 NS_DECL_NSIRUNNABLE
178 // This runnable is used to send a message to a worker debugger.
179 class WorkerDebuggerRunnable : public WorkerRunnable {
180 protected:
181 explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate,
182 const char* aName = "WorkerDebuggerRunnable")
183 : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {}
185 virtual ~WorkerDebuggerRunnable() = default;
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,
209 const char* aName = "WorkerSyncRunnable");
211 WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
212 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
213 const char* aName = "WorkerSyncRunnable");
215 virtual ~WorkerSyncRunnable();
217 virtual bool DispatchInternal() override;
220 // This runnable is identical to WorkerSyncRunnable except it is meant to be
221 // created on and dispatched from the main thread only. Its WorkerRun/PostRun
222 // will run on the worker thread.
223 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
224 protected:
225 // Passing null for aSyncLoopTarget is allowed and will result in the behavior
226 // of a normal WorkerRunnable.
227 MainThreadWorkerSyncRunnable(
228 WorkerPrivate* aWorkerPrivate, nsIEventTarget* aSyncLoopTarget,
229 const char* aName = "MainThreadWorkerSyncRunnable")
230 : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget, aName) {
231 AssertIsOnMainThread();
234 MainThreadWorkerSyncRunnable(
235 WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
236 const char* aName = "MainThreadWorkerSyncRunnable")
237 : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget), aName) {
238 AssertIsOnMainThread();
241 virtual ~MainThreadWorkerSyncRunnable() = default;
243 private:
244 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
245 AssertIsOnMainThread();
246 return true;
249 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
250 bool aDispatchResult) override;
253 // This runnable is processed as soon as it is received by the worker,
254 // potentially running before previously queued runnables and perhaps even with
255 // other JS code executing on the stack. These runnables must not alter the
256 // state of the JS runtime and should only twiddle state values.
257 class WorkerControlRunnable : public WorkerRunnable {
258 friend class WorkerPrivate;
260 protected:
261 WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
262 const char* aName = "WorkerControlRunnable",
263 Target aTarget = WorkerThread)
264 #ifdef DEBUG
266 #else
267 : WorkerRunnable(aWorkerPrivate, aName, aTarget) {
269 #endif
271 virtual ~WorkerControlRunnable() = default;
273 nsresult Cancel() override;
275 public:
276 NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, WorkerRunnable)
278 private:
279 virtual bool DispatchInternal() override;
281 // Should only be called by WorkerPrivate::DoRunLoop.
282 using WorkerRunnable::Cancel;
285 // A convenience class for WorkerRunnables that are originated on the main
286 // thread.
287 class MainThreadWorkerRunnable : public WorkerRunnable {
288 protected:
289 explicit MainThreadWorkerRunnable(
290 WorkerPrivate* aWorkerPrivate,
291 const char* aName = "MainThreadWorkerRunnable")
292 : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {
293 AssertIsOnMainThread();
296 virtual ~MainThreadWorkerRunnable() = default;
298 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
299 AssertIsOnMainThread();
300 return true;
303 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
304 bool aDispatchResult) override {
305 AssertIsOnMainThread();
309 // A convenience class for WorkerControlRunnables that originate on the main
310 // thread.
311 class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
312 protected:
313 explicit MainThreadWorkerControlRunnable(
314 WorkerPrivate* aWorkerPrivate,
315 const char* aName = "MainThreadWorkerControlRunnable")
316 : WorkerControlRunnable(aWorkerPrivate, aName, WorkerThread) {}
318 virtual ~MainThreadWorkerControlRunnable() = default;
320 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
321 AssertIsOnMainThread();
322 return true;
325 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
326 bool aDispatchResult) override {
327 AssertIsOnMainThread();
331 // A WorkerRunnable that should be dispatched from the worker to itself for
332 // async tasks.
334 // Async tasks will almost always want to use this since
335 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
336 class WorkerSameThreadRunnable : public WorkerRunnable {
337 protected:
338 explicit WorkerSameThreadRunnable(
339 WorkerPrivate* aWorkerPrivate,
340 const char* aName = "WorkerSameThreadRunnable")
341 : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {}
343 virtual ~WorkerSameThreadRunnable() = default;
345 virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
347 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
348 bool aDispatchResult) override;
350 // We just delegate PostRun to WorkerRunnable, since it does exactly
351 // what we want.
354 // Base class for the runnable objects, which makes a synchronous call to
355 // dispatch the tasks from the worker thread to the main thread.
357 // Note that the derived class must override MainThreadRun.
358 class WorkerMainThreadRunnable : public Runnable {
359 protected:
360 WorkerPrivate* mWorkerPrivate;
361 nsCOMPtr<nsISerialEventTarget> mSyncLoopTarget;
362 const nsCString mTelemetryKey;
364 explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
365 const nsACString& aTelemetryKey);
366 ~WorkerMainThreadRunnable();
368 virtual bool MainThreadRun() = 0;
370 public:
371 // Dispatch the runnable to the main thread. If dispatch to main thread
372 // fails, or if the worker is in a state equal or greater of aFailStatus, an
373 // error will be reported on aRv. Normally you want to use 'Canceling' for
374 // aFailStatus, except if you want an infallible runnable. In this case, use
375 // 'Killing'.
376 // In that case the error MUST be propagated out to script.
377 void Dispatch(WorkerStatus aFailStatus, ErrorResult& aRv);
379 private:
380 NS_IMETHOD Run() override;
383 // This runnable is an helper class for dispatching something from a worker
384 // thread to the main-thread and back to the worker-thread. During this
385 // operation, this class will keep the worker alive.
386 // The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name
387 // says, only to release resources, no JS has to be executed, no timers, or
388 // other things. The reason of such limitations is that, in order to execute
389 // this method in any condition (also when the worker is shutting down), a
390 // Control Runnable is used, and, this could generate a reordering of existing
391 // runnables.
392 class WorkerProxyToMainThreadRunnable : public Runnable {
393 protected:
394 WorkerProxyToMainThreadRunnable();
396 virtual ~WorkerProxyToMainThreadRunnable();
398 // First this method is called on the main-thread.
399 virtual void RunOnMainThread(WorkerPrivate* aWorkerPrivate) = 0;
401 // After this second method is called on the worker-thread.
402 virtual void RunBackOnWorkerThreadForCleanup(
403 WorkerPrivate* aWorkerPrivate) = 0;
405 public:
406 bool Dispatch(WorkerPrivate* aWorkerPrivate);
408 virtual bool ForMessaging() const { return false; }
410 private:
411 NS_IMETHOD Run() override;
413 void PostDispatchOnMainThread();
415 void ReleaseWorker();
417 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
420 // This runnable is used to stop a sync loop and it's meant to be used on the
421 // main-thread only.
422 class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
423 nsresult mResult;
425 public:
426 // Passing null for aSyncLoopTarget is not allowed.
427 MainThreadStopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
428 nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
429 nsresult aResult);
431 // By default StopSyncLoopRunnables cannot be canceled since they could leave
432 // a sync loop spinning forever.
433 nsresult Cancel() override;
435 protected:
436 virtual ~MainThreadStopSyncLoopRunnable() = default;
438 private:
439 bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
440 AssertIsOnMainThread();
441 return true;
444 virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
445 bool aDispatchResult) override;
447 virtual bool WorkerRun(JSContext* aCx,
448 WorkerPrivate* aWorkerPrivate) override;
450 bool DispatchInternal() final;
453 // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript
454 // error reports, and so on) must not be delivered while that content is in the
455 // midst of being debugged; the debuggee must be allowed to complete its current
456 // JavaScript invocation and return to its own event loop. Only then is it
457 // prepared for messages sent from the worker.
459 // Runnables that need to be deferred in this way should inherit from this
460 // class. They will be routed to mMainThreadDebuggeeEventTarget, which is paused
461 // while the window is suspended, as it is whenever the debugger spins its
462 // nested event loop. When the debugger leaves its nested event loop, it resumes
463 // the window, so that mMainThreadDebuggeeEventTarget will resume delivering
464 // runnables from the worker when control returns to the main event loop.
466 // When a page enters the bfcache, it freezes all its workers. Since a frozen
467 // worker processes only control runnables, it doesn't take any special
468 // consideration to prevent WorkerDebuggeeRunnables sent from child to parent
469 // workers from running; they'll never run anyway. But WorkerDebuggeeRunnables
470 // from a top-level frozen worker to its parent window must not be delivered
471 // either, even as the main thread event loop continues to spin. Thus, freezing
472 // a top-level worker also pauses mMainThreadDebuggeeEventTarget.
473 class WorkerDebuggeeRunnable : public WorkerRunnable {
474 protected:
475 WorkerDebuggeeRunnable(WorkerPrivate* aWorkerPrivate,
476 Target aTarget = ParentThread)
477 : WorkerRunnable(aWorkerPrivate, "WorkerDebuggeeRunnable", aTarget) {}
479 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
481 private:
482 // This override is deliberately private: it doesn't make sense to call it if
483 // we know statically that we are a WorkerDebuggeeRunnable.
484 bool IsDebuggeeRunnable() const override { return true; }
486 // Runnables sent upwards, to the content window or parent worker, must keep
487 // their sender alive until they are delivered: they check back with the
488 // sender in case it has been terminated after having dispatched the runnable
489 // (in which case it should not be acted upon); and runnables sent to content
490 // wait until delivery to determine the target window, since
491 // WorkerPrivate::GetWindow may only be used on the main thread.
493 // Runnables sent downwards, from content to a worker or from a worker to a
494 // child, keep the sender alive because they are WorkerThread
495 // runnables, and so leave this null.
496 RefPtr<ThreadSafeWorkerRef> mSender;
499 } // namespace dom
500 } // namespace mozilla
502 #endif // mozilla_dom_workers_workerrunnable_h__