dom/workers/WorkerRunnable.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef mozilla_dom_workers_workerrunnable_h__
     7 #define mozilla_dom_workers_workerrunnable_h__
     9 #include "Workers.h"
    11 #include "nsICancelableRunnable.h"
    13 #include "mozilla/Atomics.h"
    14 #include "nsISupportsImpl.h"
    16 class JSContext;
    17 class nsIEventTarget;
    19 BEGIN_WORKERS_NAMESPACE
    21 class WorkerPrivate;
    23 // Use this runnable to communicate from the worker to its parent or vice-versa.
    24 // The busy count must be taken into consideration and declared at construction
    25 // time.
    26 class WorkerRunnable : public nsICancelableRunnable
    27 {
    28 public:
    29   enum TargetAndBusyBehavior {
    30     // Target the main thread for top-level workers, otherwise target the
    31     // WorkerThread of the worker's parent. No change to the busy count.
    32     ParentThreadUnchangedBusyCount,
    34     // Target the thread where the worker event loop runs. The busy count will
    35     // be incremented before dispatching and decremented (asynchronously) after
    36     // running.
    37     WorkerThreadModifyBusyCount,
    39     // Target the thread where the worker event loop runs. The busy count will
    40     // not be modified in any way. Besides worker-internal runnables this is
    41     // almost always the wrong choice.
    42     WorkerThreadUnchangedBusyCount
    43   };
    45 protected:
    46   // The WorkerPrivate that this runnable is associated with.
    47   WorkerPrivate* mWorkerPrivate;
    49   // See above.
    50   TargetAndBusyBehavior mBehavior;
    52   // It's unclear whether or not Cancel() is supposed to work when called on any
    53   // thread. To be safe we're using an atomic but it's likely overkill.
    54   Atomic<uint32_t> mCanceled;
    56 private:
    57   // Whether or not Cancel() is currently being called from inside the Run()
    58   // method. Avoids infinite recursion when a subclass calls Run() from inside
    59   // Cancel(). Only checked and modified on the target thread.
    60   bool mCallingCancelWithinRun;
    62 public:
    63   NS_DECL_THREADSAFE_ISUPPORTS
    65   // If you override Cancel() then you'll need to either call the base class
    66   // Cancel() method or override IsCanceled() so that the Run() method bails out
    67   // appropriately.
    68   NS_DECL_NSICANCELABLERUNNABLE
    70   // Passing a JSContext here is required for the WorkerThreadModifyBusyCount
    71   // behavior. It also guarantees that any failure (false return) will throw an
    72   // exception on the given context. If a context is not passed then failures
    73   // must be dealt with by the caller.
    74   bool
    75   Dispatch(JSContext* aCx);
    77   // See above note about Cancel().
    78   virtual bool
    79   IsCanceled() const
    80   {
    81     return mCanceled != 0;
    82   }
    84   static WorkerRunnable*
    85   FromRunnable(nsIRunnable* aRunnable);
    87 protected:
    88   WorkerRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior)
    89 #ifdef DEBUG
    90   ;
    91 #else
    92   : mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0),
    93     mCallingCancelWithinRun(false)
    94   { }
    95 #endif
    97   // This class is reference counted.
    98   virtual ~WorkerRunnable()
    99   { }
   101   // By default asserts that Dispatch() is being called on the right thread
   102   // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
   103   // Also increments the busy count of |mWorkerPrivate| if targeting the
   104   // WorkerThread.
   105   virtual bool
   106   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
   108   // By default asserts that Dispatch() is being called on the right thread
   109   // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
   110   // Also reports any Dispatch() failures as an exception on |aCx|, and
   111   // busy count if targeting the WorkerThread and Dispatch() failed.
   112   virtual void
   113   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
   114                bool aDispatchResult);
   116   // Must be implemented by subclasses. Called on the target thread.
   117   virtual bool
   118   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
   120   // By default asserts that Run() (and WorkerRun()) were called on the correct
   121   // thread. Any failures (false return from WorkerRun) are reported on |aCx|.
   122   // Also sends an asynchronous message to the ParentThread if the busy
   123   // count was previously modified in PreDispatch().
   124   virtual void
   125   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
   127   virtual bool
   128   DispatchInternal();
   130   // Calling Run() directly is not supported. Just call Dispatch() and
   131   // WorkerRun() will be called on the correct thread automatically.
   132   NS_DECL_NSIRUNNABLE
   133 };
   135 // This runnable is used to send a message directly to a worker's sync loop.
   136 class WorkerSyncRunnable : public WorkerRunnable
   137 {
   138 protected:
   139   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
   141   // Passing null for aSyncLoopTarget is allowed and will result in the behavior
   142   // of a normal WorkerRunnable.
   143   WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
   144                      nsIEventTarget* aSyncLoopTarget);
   146   WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
   147                      already_AddRefed<nsIEventTarget>&& aSyncLoopTarget);
   149   virtual ~WorkerSyncRunnable();
   151 private:
   152   virtual bool
   153   DispatchInternal() MOZ_OVERRIDE;
   154 };
   156 // This runnable is identical to WorkerSyncRunnable except it is meant to be
   157 // used on the main thread only.
   158 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable
   159 {
   160 protected:
   161   // Passing null for aSyncLoopTarget is allowed and will result in the behavior
   162   // of a normal WorkerRunnable.
   163   MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
   164                                nsIEventTarget* aSyncLoopTarget)
   165   : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget)
   166   {
   167     AssertIsOnMainThread();
   168   }
   170   MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
   171                                already_AddRefed<nsIEventTarget>&& aSyncLoopTarget)
   172   : WorkerSyncRunnable(aWorkerPrivate, Move(aSyncLoopTarget))
   173   {
   174     AssertIsOnMainThread();
   175   }
   177   virtual ~MainThreadWorkerSyncRunnable()
   178   { }
   180 private:
   181   virtual bool
   182   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
   183   {
   184     AssertIsOnMainThread();
   185     return true;
   186   }
   188   virtual void
   189   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
   190                bool aDispatchResult) MOZ_OVERRIDE;
   191 };
   193 // This runnable is used to stop a sync loop . As sync loops keep the busy count
   194 // incremented as long as they run this runnable does not modify the busy count
   195 // in any way.
   196 class StopSyncLoopRunnable : public WorkerSyncRunnable
   197 {
   198   bool mResult;
   200 public:
   201   // Passing null for aSyncLoopTarget is not allowed.
   202   StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
   203                        already_AddRefed<nsIEventTarget>&& aSyncLoopTarget,
   204                        bool aResult);
   206   // By default StopSyncLoopRunnables cannot be canceled since they could leave
   207   // a sync loop spinning forever.
   208   NS_DECL_NSICANCELABLERUNNABLE
   210 protected:
   211   virtual ~StopSyncLoopRunnable()
   212   { }
   214   // Called on the worker thread to set an exception on the context if mResult
   215   // is false. Override if you need an exception.
   216   virtual void
   217   MaybeSetException(JSContext* aCx)
   218   { }
   220 private:
   221   virtual bool
   222   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
   224   virtual bool
   225   DispatchInternal() MOZ_OVERRIDE;
   226 };
   228 // This runnable is identical to StopSyncLoopRunnable except it is meant to be
   229 // used on the main thread only.
   230 class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable
   231 {
   232 public:
   233   // Passing null for aSyncLoopTarget is not allowed.
   234   MainThreadStopSyncLoopRunnable(
   235                                WorkerPrivate* aWorkerPrivate,
   236                                already_AddRefed<nsIEventTarget>&& aSyncLoopTarget,
   237                                bool aResult)
   238   : StopSyncLoopRunnable(aWorkerPrivate, Move(aSyncLoopTarget), aResult)
   239   {
   240     AssertIsOnMainThread();
   241   }
   243 protected:
   244   virtual ~MainThreadStopSyncLoopRunnable()
   245   { }
   247 private:
   248   virtual bool
   249   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
   250   {
   251     AssertIsOnMainThread();
   252     return true;
   253   }
   255   virtual void
   256   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
   257                bool aDispatchResult) MOZ_OVERRIDE;
   258 };
   260 // This runnable is processed as soon as it is received by the worker,
   261 // potentially running before previously queued runnables and perhaps even with
   262 // other JS code executing on the stack. These runnables must not alter the
   263 // state of the JS runtime and should only twiddle state values. The busy count
   264 // is never modified.
   265 class WorkerControlRunnable : public WorkerRunnable
   266 {
   267   friend class WorkerPrivate;
   269 protected:
   270   WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
   271                         TargetAndBusyBehavior aBehavior)
   272 #ifdef DEBUG
   273   ;
   274 #else
   275   : WorkerRunnable(aWorkerPrivate, aBehavior)
   276   { }
   277 #endif
   279   virtual ~WorkerControlRunnable()
   280   { }
   282 public:
   283   NS_DECL_ISUPPORTS_INHERITED
   285 private:
   286   virtual bool
   287   DispatchInternal() MOZ_OVERRIDE;
   289   // Should only be called by WorkerPrivate::DoRunLoop.
   290   using WorkerRunnable::Cancel;
   291 };
   293 // A convenience class for WorkerControlRunnables that originate on the main
   294 // thread.
   295 class MainThreadWorkerControlRunnable : public WorkerControlRunnable
   296 {
   297 protected:
   298   MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
   299   : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
   300   { }
   302   virtual ~MainThreadWorkerControlRunnable()
   303   { }
   305   virtual bool
   306   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
   307   {
   308     AssertIsOnMainThread();
   309     return true;
   310   }
   312   virtual void
   313   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
   314                bool aDispatchResult) MOZ_OVERRIDE;
   315 };
   317 // A WorkerRunnable that should be dispatched from the worker to itself for
   318 // async tasks. This will increment the busy count PostDispatch() (only if
   319 // dispatch was successful) and decrement it in PostRun().
   320 //
   321 // Async tasks will almost always want to use this since
   322 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
   323 class WorkerSameThreadRunnable : public WorkerRunnable
   324 {
   325 protected:
   326   WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
   327   : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
   328   { }
   330   virtual ~WorkerSameThreadRunnable()
   331   { }
   333   virtual bool
   334   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
   336   virtual void
   337   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
   338                bool aDispatchResult) MOZ_OVERRIDE;
   340   virtual void
   341   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
   342           bool aRunResult) MOZ_OVERRIDE;
   343 };
   345 END_WORKERS_NAMESPACE
   347 #endif // mozilla_dom_workers_workerrunnable_h__

mercurial