diff options
Diffstat (limited to 'dom/workers/WorkerRunnable.h')
-rw-r--r-- | dom/workers/WorkerRunnable.h | 304 |
1 files changed, 188 insertions, 116 deletions
diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h index d133f11ea2..d404e12d8d 100644 --- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -12,8 +12,11 @@ #include "MainThreadUtils.h" #include "mozilla/Atomics.h" #include "mozilla/RefPtr.h" +#include "mozilla/ThreadSafeWeakPtr.h" +#include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" #include "mozilla/dom/WorkerStatus.h" +#include "mozilla/dom/quota/CheckedUnsafePtr.h" #include "nsCOMPtr.h" #include "nsIRunnable.h" #include "nsISupports.h" @@ -31,53 +34,30 @@ class ErrorResult; namespace dom { -class WorkerPrivate; +class Worker; -// Use this runnable to communicate from the worker to its parent or vice-versa. class WorkerRunnable : public nsIRunnable #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY , public nsINamed #endif { - public: - enum Target { - // Target the main thread for top-level workers, otherwise target the - // WorkerThread of the worker's parent. - ParentThread, - - // Target the thread where the worker event loop runs. - WorkerThread, - }; - protected: - // The WorkerPrivate that this runnable is associated with. - WorkerPrivate* mWorkerPrivate; - - // See above. - Target mTarget; - #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY const char* mName = nullptr; #endif - private: - // Whether or not Cancel() is currently being called from inside the Run() - // method. Avoids infinite recursion when a subclass calls Run() from inside - // Cancel(). Only checked and modified on the target thread. - bool mCallingCancelWithinRun; - public: NS_DECL_THREADSAFE_ISUPPORTS #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY NS_DECL_NSINAMED #endif - virtual nsresult Cancel(); + virtual nsresult Cancel() = 0; // The return value is true if and only if both PreDispatch and // DispatchInternal return true. - bool Dispatch(); + virtual bool Dispatch(WorkerPrivate* aWorkerPrivate); // True if this runnable is handled by running JavaScript in some global that // could possibly be a debuggee, and thus needs to be deferred when the target @@ -90,41 +70,43 @@ class WorkerRunnable : public nsIRunnable // support debugging the debugger server at the moment. virtual bool IsDebuggeeRunnable() const { return false; } + // True if this runnable needs to be dispatched to + // WorkerPrivate::mControlEventTareget. + virtual bool IsControlRunnable() const { return false; } + + // True if this runnable should be dispatched to the debugger queue, + // and false otherwise. + virtual bool IsDebuggerRunnable() const { return false; } + static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable); protected: - WorkerRunnable(WorkerPrivate* aWorkerPrivate, - const char* aName = "WorkerRunnable", - Target aTarget = WorkerThread) + explicit WorkerRunnable(const char* aName = "WorkerRunnable") #ifdef DEBUG ; #else - : mWorkerPrivate(aWorkerPrivate), - mTarget(aTarget), # ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY - mName(aName), + : mName(aName) # endif - mCallingCancelWithinRun(false) { + { } #endif // This class is reference counted. virtual ~WorkerRunnable() = default; - // Returns true if this runnable should be dispatched to the debugger queue, - // and false otherwise. - virtual bool IsDebuggerRunnable() const; - - nsIGlobalObject* DefaultGlobalObject() const; + // Calling Run() directly is not supported. Just call Dispatch() and + // WorkerRun() will be called on the correct thread automatically. + NS_DECL_NSIRUNNABLE // By default asserts that Dispatch() is being called on the right thread - // (ParentThread if |mTarget| is WorkerThread). - virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate); + virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) = 0; // By default asserts that Dispatch() is being called on the right thread - // (ParentThread if |mTarget| is WorkerThread). virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, - bool aDispatchResult); + bool aDispatchResult) = 0; + + virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) = 0; // May be implemented by subclasses if desired if they need to do some sort of // setup before we try to set up our JSContext and compartment for real. @@ -133,17 +115,19 @@ class WorkerRunnable : public nsIRunnable // // If false is returned, WorkerRun will not be called at all. PostRun will // still be called, with false passed for aRunResult. - virtual bool PreRun(WorkerPrivate* aWorkerPrivate); + virtual bool PreRun(WorkerPrivate* aWorkerPrivate) = 0; // Must be implemented by subclasses. Called on the target thread. The return // value will be passed to PostRun(). The JSContext passed in here comes from - // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If - // mTarget is ParentThread, it is in the compartment of + // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. + // + // If the runnable is for parent thread, aCx is in the compartment of // mWorkerPrivate's reflector (i.e. the worker object in the parent thread), // unless that reflector is null, in which case it's in the compartment of the // parent global (which is the compartment reflector would have been in), or - // in the null compartment if there is no parent global. For other mTarget - // values, we're running on the worker thread and aCx is in whatever + // in the null compartment if there is no parent global. + // + // For runnables on the worker thread, aCx is in whatever // compartment GetCurrentWorkerThreadJSContext() was in when // nsIRunnable::Run() got called. This is actually important for cases when a // runnable spins a syncloop and wants everything that happens during the @@ -166,21 +150,138 @@ class WorkerRunnable : public nsIRunnable // exception on the JSContext and must not run script, because the incoming // JSContext may be in the null compartment. virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aRunResult); + bool aRunResult) = 0; +}; + +class WorkerParentThreadRunnable : public WorkerRunnable { + public: + NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentThreadRunnable, + WorkerRunnable) + + virtual nsresult Cancel() override; + + protected: + explicit WorkerParentThreadRunnable( + const char* aName = "WorkerParentThreadRunnable"); + + // This class is reference counted. + virtual ~WorkerParentThreadRunnable(); + + virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override; + + virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) override; + + virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override; + + virtual bool WorkerRun(JSContext* aCx, + WorkerPrivate* aWorkerPrivate) override = 0; + + virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aRunResult) override; + + virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final; + + // Calling Run() directly is not supported. Just call Dispatch() and + // WorkerRun() will be called on the correct thread automatically. + NS_DECL_NSIRUNNABLE + + private: + RefPtr<WorkerParentRef> mWorkerParentRef; +}; + +class WorkerParentControlRunnable : public WorkerParentThreadRunnable { + friend class WorkerPrivate; + + protected: + explicit WorkerParentControlRunnable( + const char* aName = "WorkerParentControlRunnable"); + + virtual ~WorkerParentControlRunnable(); + + nsresult Cancel() override; + + public: + NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentControlRunnable, + WorkerParentThreadRunnable) + + private: + bool IsControlRunnable() const override { return true; } + + // Should only be called by WorkerPrivate::DoRunLoop. + using WorkerParentThreadRunnable::Cancel; +}; + +class WorkerParentDebuggeeRunnable : public WorkerParentThreadRunnable { + protected: + explicit WorkerParentDebuggeeRunnable( + const char* aName = "WorkerParentDebuggeeRunnable") + : WorkerParentThreadRunnable(aName) {} + + private: + // This override is deliberately private: it doesn't make sense to call it if + // we know statically that we are a WorkerDebuggeeRunnable. + bool IsDebuggeeRunnable() const override { return true; } +}; + +class WorkerThreadRunnable : public WorkerRunnable { + friend class WorkerPrivate; + + public: + NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerThreadRunnable, WorkerRunnable) + + virtual nsresult Cancel() override; + + protected: + explicit WorkerThreadRunnable(const char* aName = "WorkerThreadRunnable"); + + // This class is reference counted. + virtual ~WorkerThreadRunnable() = default; + + nsIGlobalObject* DefaultGlobalObject(WorkerPrivate* aWorkerPrivate) const; + + virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override; + + virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) override; + + virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override; + + virtual bool WorkerRun(JSContext* aCx, + WorkerPrivate* aWorkerPrivate) override = 0; + + virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aRunResult) override; - virtual bool DispatchInternal(); + virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override; // Calling Run() directly is not supported. Just call Dispatch() and // WorkerRun() will be called on the correct thread automatically. NS_DECL_NSIRUNNABLE + + // Whether or not Cancel() is currently being called from inside the Run() + // method. Avoids infinite recursion when a subclass calls Run() from inside + // Cancel(). Only checked and modified on the target thread. + bool mCallingCancelWithinRun; + + // If dispatching a WorkerThreadRunnable before Worker initialization complete + // in worker thread, which are in WorkerPrivate::mPreStartRunnables, when + // GetCurrentThreadWorkerPrivate() might get an invalid WorkerPrivate for + // WorkerThreadRunnable::Run() because it is in Worker's shutdown. + // + // This is specific for cleanup these pre-start runnables if the shutdown + // starts before Worker executes its event loop. + // This member is only set when the runnable is dispatched to + // WorkerPrivate::mPreStartRunnables. Any other cases to use this + // WorkerPrivate is always wrong. + CheckedUnsafePtr<WorkerPrivate> mWorkerPrivateForPreStartCleaning; }; // This runnable is used to send a message to a worker debugger. -class WorkerDebuggerRunnable : public WorkerRunnable { +class WorkerDebuggerRunnable : public WorkerThreadRunnable { protected: - explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate, - const char* aName = "WorkerDebuggerRunnable") - : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {} + explicit WorkerDebuggerRunnable(const char* aName = "WorkerDebuggerRunnable") + : WorkerThreadRunnable(aName) {} virtual ~WorkerDebuggerRunnable() = default; @@ -198,23 +299,21 @@ class WorkerDebuggerRunnable : public WorkerRunnable { }; // This runnable is used to send a message directly to a worker's sync loop. -class WorkerSyncRunnable : public WorkerRunnable { +class WorkerSyncRunnable : public WorkerThreadRunnable { protected: nsCOMPtr<nsIEventTarget> mSyncLoopTarget; // Passing null for aSyncLoopTarget is allowed and will result in the behavior - // of a normal WorkerRunnable. - WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, - nsIEventTarget* aSyncLoopTarget, - const char* aName = "WorkerSyncRunnable"); + // of a normal WorkerThreadRunnable. + explicit WorkerSyncRunnable(nsIEventTarget* aSyncLoopTarget, + const char* aName = "WorkerSyncRunnable"); - WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, - nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, - const char* aName = "WorkerSyncRunnable"); + explicit WorkerSyncRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, + const char* aName = "WorkerSyncRunnable"); virtual ~WorkerSyncRunnable(); - virtual bool DispatchInternal() override; + virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override; }; // This runnable is identical to WorkerSyncRunnable except it is meant to be @@ -223,18 +322,18 @@ class WorkerSyncRunnable : public WorkerRunnable { class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable { protected: // Passing null for aSyncLoopTarget is allowed and will result in the behavior - // of a normal WorkerRunnable. - MainThreadWorkerSyncRunnable( - WorkerPrivate* aWorkerPrivate, nsIEventTarget* aSyncLoopTarget, + // of a normal WorkerThreadRunnable. + explicit MainThreadWorkerSyncRunnable( + nsIEventTarget* aSyncLoopTarget, const char* aName = "MainThreadWorkerSyncRunnable") - : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget, aName) { + : WorkerSyncRunnable(aSyncLoopTarget, aName) { AssertIsOnMainThread(); } - MainThreadWorkerSyncRunnable( - WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, + explicit MainThreadWorkerSyncRunnable( + nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, const char* aName = "MainThreadWorkerSyncRunnable") - : WorkerSyncRunnable(aWorkerPrivate, std::move(aSyncLoopTarget), aName) { + : WorkerSyncRunnable(std::move(aSyncLoopTarget), aName) { AssertIsOnMainThread(); } @@ -254,42 +353,34 @@ class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable { // potentially running before previously queued runnables and perhaps even with // other JS code executing on the stack. These runnables must not alter the // state of the JS runtime and should only twiddle state values. -class WorkerControlRunnable : public WorkerRunnable { +class WorkerControlRunnable : public WorkerThreadRunnable { friend class WorkerPrivate; protected: - WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, - const char* aName = "WorkerControlRunnable", - Target aTarget = WorkerThread) -#ifdef DEBUG - ; -#else - : WorkerRunnable(aWorkerPrivate, aName, aTarget) { - } -#endif + explicit WorkerControlRunnable(const char* aName = "WorkerControlRunnable"); virtual ~WorkerControlRunnable() = default; nsresult Cancel() override; public: - NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, WorkerRunnable) + NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable, + WorkerThreadRunnable) private: - virtual bool DispatchInternal() override; + bool IsControlRunnable() const override { return true; } // Should only be called by WorkerPrivate::DoRunLoop. - using WorkerRunnable::Cancel; + using WorkerThreadRunnable::Cancel; }; -// A convenience class for WorkerRunnables that are originated on the main +// A convenience class for WorkerThreadRunnables that are originated on the main // thread. -class MainThreadWorkerRunnable : public WorkerRunnable { +class MainThreadWorkerRunnable : public WorkerThreadRunnable { protected: explicit MainThreadWorkerRunnable( - WorkerPrivate* aWorkerPrivate, const char* aName = "MainThreadWorkerRunnable") - : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) { + : WorkerThreadRunnable(aName) { AssertIsOnMainThread(); } @@ -311,9 +402,8 @@ class MainThreadWorkerRunnable : public WorkerRunnable { class MainThreadWorkerControlRunnable : public WorkerControlRunnable { protected: explicit MainThreadWorkerControlRunnable( - WorkerPrivate* aWorkerPrivate, const char* aName = "MainThreadWorkerControlRunnable") - : WorkerControlRunnable(aWorkerPrivate, aName, WorkerThread) {} + : WorkerControlRunnable(aName) {} virtual ~MainThreadWorkerControlRunnable() = default; @@ -328,17 +418,16 @@ class MainThreadWorkerControlRunnable : public WorkerControlRunnable { } }; -// A WorkerRunnable that should be dispatched from the worker to itself for -// async tasks. +// A WorkerThreadRunnable that should be dispatched from the worker to itself +// for async tasks. // // Async tasks will almost always want to use this since // a WorkerSameThreadRunnable keeps the Worker from being GCed. -class WorkerSameThreadRunnable : public WorkerRunnable { +class WorkerSameThreadRunnable : public WorkerThreadRunnable { protected: explicit WorkerSameThreadRunnable( - WorkerPrivate* aWorkerPrivate, const char* aName = "WorkerSameThreadRunnable") - : WorkerRunnable(aWorkerPrivate, aName, WorkerThread) {} + : WorkerThreadRunnable(aName) {} virtual ~WorkerSameThreadRunnable() = default; @@ -347,7 +436,7 @@ class WorkerSameThreadRunnable : public WorkerRunnable { virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override; - // We just delegate PostRun to WorkerRunnable, since it does exactly + // We just delegate PostRun to WorkerThreadRunnable, since it does exactly // what we want. }; @@ -424,8 +513,7 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable { public: // Passing null for aSyncLoopTarget is not allowed. - MainThreadStopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate, - nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, + MainThreadStopSyncLoopRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget, nsresult aResult); // By default StopSyncLoopRunnables cannot be canceled since they could leave @@ -447,7 +535,7 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable { virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; - bool DispatchInternal() final; + bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final; }; // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript @@ -470,31 +558,15 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable { // from a top-level frozen worker to its parent window must not be delivered // either, even as the main thread event loop continues to spin. Thus, freezing // a top-level worker also pauses mMainThreadDebuggeeEventTarget. -class WorkerDebuggeeRunnable : public WorkerRunnable { +class WorkerDebuggeeRunnable : public WorkerThreadRunnable { protected: - WorkerDebuggeeRunnable(WorkerPrivate* aWorkerPrivate, - const char* aName = "WorkerDebuggeeRunnable", - Target aTarget = ParentThread) - : WorkerRunnable(aWorkerPrivate, aName, aTarget) {} - - bool PreDispatch(WorkerPrivate* aWorkerPrivate) override; + explicit WorkerDebuggeeRunnable(const char* aName = "WorkerDebuggeeRunnable") + : WorkerThreadRunnable(aName) {} private: // This override is deliberately private: it doesn't make sense to call it if // we know statically that we are a WorkerDebuggeeRunnable. bool IsDebuggeeRunnable() const override { return true; } - - // Runnables sent upwards, to the content window or parent worker, must keep - // their sender alive until they are delivered: they check back with the - // sender in case it has been terminated after having dispatched the runnable - // (in which case it should not be acted upon); and runnables sent to content - // wait until delivery to determine the target window, since - // WorkerPrivate::GetWindow may only be used on the main thread. - // - // Runnables sent downwards, from content to a worker or from a worker to a - // child, keep the sender alive because they are WorkerThread - // runnables, and so leave this null. - RefPtr<ThreadSafeWorkerRef> mSender; }; } // namespace dom |