tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WorkerRunnable.h (20267B)


      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/. */
      6 
      7 #ifndef mozilla_dom_workers_workerrunnable_h__
      8 #define mozilla_dom_workers_workerrunnable_h__
      9 
     10 #include <utility>
     11 
     12 #include "MainThreadUtils.h"
     13 #include "mozilla/RefPtr.h"
     14 #include "mozilla/dom/WorkerPrivate.h"
     15 #include "mozilla/dom/WorkerRef.h"
     16 #include "mozilla/dom/WorkerStatus.h"
     17 #include "mozilla/dom/quota/CheckedUnsafePtr.h"
     18 #include "nsCOMPtr.h"
     19 #include "nsIRunnable.h"
     20 #include "nsISupports.h"
     21 #include "nsStringFwd.h"
     22 #include "nsThreadUtils.h"
     23 #include "nscore.h"
     24 
     25 struct JSContext;
     26 class nsIEventTarget;
     27 class nsIGlobalObject;
     28 
     29 namespace mozilla {
     30 
     31 class ErrorResult;
     32 
     33 namespace dom {
     34 
     35 class Worker;
     36 
     37 class WorkerRunnable : public nsIRunnable
     38 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
     39    ,
     40                       public nsINamed
     41 #endif
     42 {
     43 protected:
     44 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
     45  const char* mName = nullptr;
     46 #endif
     47 
     48 public:
     49  NS_DECL_THREADSAFE_ISUPPORTS
     50 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
     51  NS_DECL_NSINAMED
     52 #endif
     53 
     54  virtual nsresult Cancel() = 0;
     55 
     56  // The return value is true if and only if both PreDispatch and
     57  // DispatchInternal return true.
     58  virtual bool Dispatch(WorkerPrivate* aWorkerPrivate);
     59 
     60  // True if this runnable is handled by running JavaScript in some global that
     61  // could possibly be a debuggee, and thus needs to be deferred when the target
     62  // is paused in the debugger, until the JavaScript invocation in progress has
     63  // run to completion. Examples are MessageEventRunnable and
     64  // ReportErrorRunnable. These runnables are segregated into separate
     65  // ThrottledEventQueues, which the debugger pauses.
     66  //
     67  // Note that debugger runnables do not fall in this category, since we don't
     68  // support debugging the debugger server at the moment.
     69  virtual bool IsDebuggeeRunnable() const { return false; }
     70 
     71  // True if this runnable needs to be dispatched to
     72  // WorkerPrivate::mControlEventTareget.
     73  virtual bool IsControlRunnable() const { return false; }
     74 
     75  // True if this runnable should be dispatched to the debugger queue,
     76  // and false otherwise.
     77  virtual bool IsDebuggerRunnable() const { return false; }
     78 
     79  static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
     80 
     81 protected:
     82  explicit WorkerRunnable(const char* aName = "WorkerRunnable")
     83 #ifdef DEBUG
     84      ;
     85 #else
     86 #  ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
     87      : mName(aName)
     88 #  endif
     89  {
     90  }
     91 #endif
     92 
     93  // This class is reference counted.
     94  virtual ~WorkerRunnable() = default;
     95 
     96  // Calling Run() directly is not supported. Just call Dispatch() and
     97  // WorkerRun() will be called on the correct thread automatically.
     98  NS_DECL_NSIRUNNABLE
     99 
    100  // By default asserts that Dispatch() is being called on the right thread
    101  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) = 0;
    102 
    103  // By default asserts that Dispatch() is being called on the right thread
    104  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    105                            bool aDispatchResult) = 0;
    106 
    107  virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) = 0;
    108 
    109  // May be implemented by subclasses if desired if they need to do some sort of
    110  // setup before we try to set up our JSContext and compartment for real.
    111  // Typically the only thing that should go in here is creation of the worker's
    112  // global.
    113  //
    114  // If false is returned, WorkerRun will not be called at all.  PostRun will
    115  // still be called, with false passed for aRunResult.
    116  virtual bool PreRun(WorkerPrivate* aWorkerPrivate) = 0;
    117 
    118  // Must be implemented by subclasses. Called on the target thread.  The return
    119  // value will be passed to PostRun().  The JSContext passed in here comes from
    120  // an AutoJSAPI (or AutoEntryScript) that we set up on the stack.
    121  //
    122  // If the runnable is for parent thread, aCx is in the compartment of
    123  // mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
    124  // unless that reflector is null, in which case it's in the compartment of the
    125  // parent global (which is the compartment reflector would have been in), or
    126  // in the null compartment if there is no parent global.
    127  //
    128  // For runnables on the worker thread, aCx is in whatever
    129  // compartment GetCurrentWorkerThreadJSContext() was in when
    130  // nsIRunnable::Run() got called.  This is actually important for cases when a
    131  // runnable spins a syncloop and wants everything that happens during the
    132  // syncloop to happen in the compartment that runnable set up (which may, for
    133  // example, be a debugger sandbox compartment!).  If aCx wasn't in a
    134  // compartment to start with, aCx will be in either the debugger global's
    135  // compartment or the worker's global's compartment depending on whether
    136  // IsDebuggerRunnable() is true.
    137  //
    138  // Immediately after WorkerRun returns, the caller will assert that either it
    139  // returns false or there is no exception pending on aCx.  Then it will report
    140  // any pending exceptions on aCx.
    141  virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
    142 
    143  // By default asserts that Run() (and WorkerRun()) were called on the correct
    144  // thread.
    145  //
    146  // The aCx passed here is the same one as was passed to WorkerRun and is
    147  // still in the same compartment.  PostRun implementations must NOT leave an
    148  // exception on the JSContext and must not run script, because the incoming
    149  // JSContext may be in the null compartment.
    150  virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
    151                       bool aRunResult) = 0;
    152 };
    153 
    154 class WorkerParentThreadRunnable : public WorkerRunnable {
    155 public:
    156  NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentThreadRunnable,
    157                                       WorkerRunnable)
    158 
    159  virtual nsresult Cancel() override;
    160 
    161 protected:
    162  explicit WorkerParentThreadRunnable(
    163      const char* aName = "WorkerParentThreadRunnable");
    164 
    165  // This class is reference counted.
    166  virtual ~WorkerParentThreadRunnable();
    167 
    168  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
    169 
    170  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    171                            bool aDispatchResult) override;
    172 
    173  virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override;
    174 
    175  virtual bool WorkerRun(JSContext* aCx,
    176                         WorkerPrivate* aWorkerPrivate) override = 0;
    177 
    178  virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
    179                       bool aRunResult) override;
    180 
    181  virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final;
    182 
    183  // Calling Run() directly is not supported. Just call Dispatch() and
    184  // WorkerRun() will be called on the correct thread automatically.
    185  NS_DECL_NSIRUNNABLE
    186 
    187 private:
    188  RefPtr<WorkerParentRef> mWorkerParentRef;
    189 };
    190 
    191 class WorkerParentControlRunnable : public WorkerParentThreadRunnable {
    192  friend class WorkerPrivate;
    193 
    194 protected:
    195  explicit WorkerParentControlRunnable(
    196      const char* aName = "WorkerParentControlRunnable");
    197 
    198  virtual ~WorkerParentControlRunnable();
    199 
    200  nsresult Cancel() override;
    201 
    202 public:
    203  NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerParentControlRunnable,
    204                                       WorkerParentThreadRunnable)
    205 
    206 private:
    207  bool IsControlRunnable() const override { return true; }
    208 
    209  // Should only be called by WorkerPrivate::DoRunLoop.
    210  using WorkerParentThreadRunnable::Cancel;
    211 };
    212 
    213 class WorkerParentDebuggeeRunnable : public WorkerParentThreadRunnable {
    214 protected:
    215  explicit WorkerParentDebuggeeRunnable(
    216      const char* aName = "WorkerParentDebuggeeRunnable")
    217      : WorkerParentThreadRunnable(aName) {}
    218 
    219 private:
    220  // This override is deliberately private: it doesn't make sense to call it if
    221  // we know statically that we are a WorkerDebuggeeRunnable.
    222  bool IsDebuggeeRunnable() const override { return true; }
    223 };
    224 
    225 class WorkerThreadRunnable : public WorkerRunnable {
    226  friend class WorkerPrivate;
    227 
    228 public:
    229  NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerThreadRunnable, WorkerRunnable)
    230 
    231  virtual nsresult Cancel() override;
    232 
    233 protected:
    234  explicit WorkerThreadRunnable(const char* aName = "WorkerThreadRunnable");
    235 
    236  // This class is reference counted.
    237  virtual ~WorkerThreadRunnable() = default;
    238 
    239  nsIGlobalObject* DefaultGlobalObject(WorkerPrivate* aWorkerPrivate) const;
    240 
    241  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
    242 
    243  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    244                            bool aDispatchResult) override;
    245 
    246  virtual bool PreRun(WorkerPrivate* aWorkerPrivate) override;
    247 
    248  virtual bool WorkerRun(JSContext* aCx,
    249                         WorkerPrivate* aWorkerPrivate) override = 0;
    250 
    251  virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
    252                       bool aRunResult) override;
    253 
    254  virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override;
    255 
    256  // Calling Run() directly is not supported. Just call Dispatch() and
    257  // WorkerRun() will be called on the correct thread automatically.
    258  NS_DECL_NSIRUNNABLE
    259 
    260  // Whether or not Cancel() is currently being called from inside the Run()
    261  // method. Avoids infinite recursion when a subclass calls Run() from inside
    262  // Cancel(). Only checked and modified on the target thread.
    263  bool mCallingCancelWithinRun;
    264 
    265  bool mCleanPreStartDispatching{false};
    266 };
    267 
    268 // This runnable is used to send a message to a worker debugger.
    269 class WorkerDebuggerRunnable : public WorkerThreadRunnable {
    270 protected:
    271  explicit WorkerDebuggerRunnable(const char* aName = "WorkerDebuggerRunnable")
    272      : WorkerThreadRunnable(aName) {}
    273 
    274  virtual ~WorkerDebuggerRunnable() = default;
    275 
    276 private:
    277  virtual bool IsDebuggerRunnable() const override { return true; }
    278 
    279  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
    280    AssertIsOnMainThread();
    281 
    282    return true;
    283  }
    284 
    285  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    286                            bool aDispatchResult) override;
    287 };
    288 
    289 // This runnable is used to send a message directly to a worker's sync loop.
    290 class WorkerSyncRunnable : public WorkerThreadRunnable {
    291 protected:
    292  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
    293 
    294  // Passing null for aSyncLoopTarget is allowed and will result in the behavior
    295  // of a normal WorkerThreadRunnable.
    296  explicit WorkerSyncRunnable(nsIEventTarget* aSyncLoopTarget,
    297                              const char* aName = "WorkerSyncRunnable");
    298 
    299  explicit WorkerSyncRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
    300                              const char* aName = "WorkerSyncRunnable");
    301 
    302  virtual ~WorkerSyncRunnable();
    303 
    304  virtual bool DispatchInternal(WorkerPrivate* aWorkerPrivate) override;
    305 };
    306 
    307 // This runnable is identical to WorkerSyncRunnable except it is meant to be
    308 // created on and dispatched from the main thread only.  Its WorkerRun/PostRun
    309 // will run on the worker thread.
    310 class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
    311 protected:
    312  // Passing null for aSyncLoopTarget is allowed and will result in the behavior
    313  // of a normal WorkerThreadRunnable.
    314  explicit MainThreadWorkerSyncRunnable(
    315      nsIEventTarget* aSyncLoopTarget,
    316      const char* aName = "MainThreadWorkerSyncRunnable")
    317      : WorkerSyncRunnable(aSyncLoopTarget, aName) {
    318    AssertIsOnMainThread();
    319  }
    320 
    321  explicit MainThreadWorkerSyncRunnable(
    322      nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
    323      const char* aName = "MainThreadWorkerSyncRunnable")
    324      : WorkerSyncRunnable(std::move(aSyncLoopTarget), aName) {
    325    AssertIsOnMainThread();
    326  }
    327 
    328  virtual ~MainThreadWorkerSyncRunnable() = default;
    329 
    330 private:
    331  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
    332    AssertIsOnMainThread();
    333    return true;
    334  }
    335 
    336  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    337                            bool aDispatchResult) override;
    338 };
    339 
    340 // This runnable is processed as soon as it is received by the worker,
    341 // potentially running before previously queued runnables and perhaps even with
    342 // other JS code executing on the stack. These runnables must not alter the
    343 // state of the JS runtime and should only twiddle state values.
    344 class WorkerControlRunnable : public WorkerThreadRunnable {
    345  friend class WorkerPrivate;
    346 
    347 protected:
    348  explicit WorkerControlRunnable(const char* aName = "WorkerControlRunnable");
    349 
    350  virtual ~WorkerControlRunnable() = default;
    351 
    352  nsresult Cancel() override;
    353 
    354 public:
    355  NS_INLINE_DECL_REFCOUNTING_INHERITED(WorkerControlRunnable,
    356                                       WorkerThreadRunnable)
    357 
    358 private:
    359  bool IsControlRunnable() const override { return true; }
    360 
    361  // Should only be called by WorkerPrivate::DoRunLoop.
    362  using WorkerThreadRunnable::Cancel;
    363 };
    364 
    365 // A convenience class for WorkerThreadRunnables that are originated on the main
    366 // thread.
    367 class MainThreadWorkerRunnable : public WorkerThreadRunnable {
    368 protected:
    369  explicit MainThreadWorkerRunnable(
    370      const char* aName = "MainThreadWorkerRunnable")
    371      : WorkerThreadRunnable(aName) {
    372    AssertIsOnMainThread();
    373  }
    374 
    375  virtual ~MainThreadWorkerRunnable() = default;
    376 
    377  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
    378    AssertIsOnMainThread();
    379    return true;
    380  }
    381 
    382  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    383                            bool aDispatchResult) override {
    384    AssertIsOnMainThread();
    385  }
    386 };
    387 
    388 // A convenience class for WorkerControlRunnables that originate on the main
    389 // thread.
    390 class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
    391 protected:
    392  explicit MainThreadWorkerControlRunnable(
    393      const char* aName = "MainThreadWorkerControlRunnable")
    394      : WorkerControlRunnable(aName) {}
    395 
    396  virtual ~MainThreadWorkerControlRunnable() = default;
    397 
    398  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
    399    AssertIsOnMainThread();
    400    return true;
    401  }
    402 
    403  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    404                            bool aDispatchResult) override {
    405    AssertIsOnMainThread();
    406  }
    407 };
    408 
    409 // A WorkerThreadRunnable that should be dispatched from the worker to itself
    410 // for async tasks.
    411 //
    412 // Async tasks will almost always want to use this since
    413 // a WorkerSameThreadRunnable keeps the Worker from being GCed.
    414 class WorkerSameThreadRunnable : public WorkerThreadRunnable {
    415 protected:
    416  explicit WorkerSameThreadRunnable(
    417      const char* aName = "WorkerSameThreadRunnable")
    418      : WorkerThreadRunnable(aName) {}
    419 
    420  virtual ~WorkerSameThreadRunnable() = default;
    421 
    422  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
    423 
    424  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    425                            bool aDispatchResult) override;
    426 
    427  // We just delegate PostRun to WorkerThreadRunnable, since it does exactly
    428  // what we want.
    429 };
    430 
    431 // Base class for the runnable objects, which makes a synchronous call to
    432 // dispatch the tasks from the worker thread to the main thread.
    433 //
    434 // Note that the derived class must override MainThreadRun.
    435 class WorkerMainThreadRunnable : public Runnable {
    436 protected:
    437  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
    438  nsCOMPtr<nsISerialEventTarget> mSyncLoopTarget;
    439  const nsCString mTelemetryKey;
    440  const char* mName;
    441 
    442  explicit WorkerMainThreadRunnable(
    443      WorkerPrivate* aWorkerPrivate, const nsACString& aTelemetryKey,
    444      const char* aName = "WorkerMainThreadRunnable");
    445 
    446  ~WorkerMainThreadRunnable();
    447 
    448  virtual bool MainThreadRun() = 0;
    449 
    450 public:
    451  // Dispatch the runnable to the main thread.  If dispatch to main thread
    452  // fails, or if the worker is in a state equal or greater of aFailStatus, an
    453  // error will be reported on aRv. Normally you want to use 'Canceling' for
    454  // aFailStatus, except if you want an infallible runnable. In this case, use
    455  // 'Killing'.
    456  // In that case the error MUST be propagated out to script.
    457  void Dispatch(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus,
    458                ErrorResult& aRv);
    459 
    460 private:
    461  NS_IMETHOD Run() override;
    462 };
    463 
    464 // This runnable is an helper class for dispatching something from a worker
    465 // thread to the main-thread and back to the worker-thread. During this
    466 // operation, this class will keep the worker alive.
    467 // The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name
    468 // says, only to release resources, no JS has to be executed, no timers, or
    469 // other things. The reason of such limitations is that, in order to execute
    470 // this method in any condition (also when the worker is shutting down), a
    471 // Control Runnable is used, and, this could generate a reordering of existing
    472 // runnables.
    473 class WorkerProxyToMainThreadRunnable : public Runnable {
    474 protected:
    475  WorkerProxyToMainThreadRunnable();
    476 
    477  virtual ~WorkerProxyToMainThreadRunnable();
    478 
    479  // First this method is called on the main-thread.
    480  virtual void RunOnMainThread(WorkerPrivate* aWorkerPrivate) = 0;
    481 
    482  // After this second method is called on the worker-thread.
    483  virtual void RunBackOnWorkerThreadForCleanup(
    484      WorkerPrivate* aWorkerPrivate) = 0;
    485 
    486 public:
    487  bool Dispatch(WorkerPrivate* aWorkerPrivate);
    488 
    489  virtual bool ForMessaging() const { return false; }
    490 
    491 private:
    492  NS_IMETHOD Run() override;
    493 
    494  void PostDispatchOnMainThread();
    495 
    496  void ReleaseWorker();
    497 
    498  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
    499 };
    500 
    501 // This runnable is used to stop a sync loop and it's meant to be used on the
    502 // main-thread only.
    503 class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
    504  nsresult mResult;
    505 
    506 public:
    507  // Passing null for aSyncLoopTarget is not allowed.
    508  MainThreadStopSyncLoopRunnable(nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget,
    509                                 nsresult aResult);
    510 
    511  // By default StopSyncLoopRunnables cannot be canceled since they could leave
    512  // a sync loop spinning forever.
    513  nsresult Cancel() override;
    514 
    515 protected:
    516  virtual ~MainThreadStopSyncLoopRunnable() = default;
    517 
    518 private:
    519  bool PreDispatch(WorkerPrivate* aWorkerPrivate) final {
    520    AssertIsOnMainThread();
    521    return true;
    522  }
    523 
    524  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    525                            bool aDispatchResult) override;
    526 
    527  virtual bool WorkerRun(JSContext* aCx,
    528                         WorkerPrivate* aWorkerPrivate) override;
    529 
    530  bool DispatchInternal(WorkerPrivate* aWorkerPrivate) final;
    531 };
    532 
    533 // Runnables handled by content JavaScript (MessageEventRunnable, JavaScript
    534 // error reports, and so on) must not be delivered while that content is in the
    535 // midst of being debugged; the debuggee must be allowed to complete its current
    536 // JavaScript invocation and return to its own event loop. Only then is it
    537 // prepared for messages sent from the worker.
    538 //
    539 // Runnables that need to be deferred in this way should inherit from this
    540 // class. They will be routed to mMainThreadDebuggeeEventTarget, which is paused
    541 // while the window is suspended, as it is whenever the debugger spins its
    542 // nested event loop. When the debugger leaves its nested event loop, it resumes
    543 // the window, so that mMainThreadDebuggeeEventTarget will resume delivering
    544 // runnables from the worker when control returns to the main event loop.
    545 //
    546 // When a page enters the bfcache, it freezes all its workers. Since a frozen
    547 // worker processes only control runnables, it doesn't take any special
    548 // consideration to prevent WorkerDebuggeeRunnables sent from child to parent
    549 // workers from running; they'll never run anyway. But WorkerDebuggeeRunnables
    550 // from a top-level frozen worker to its parent window must not be delivered
    551 // either, even as the main thread event loop continues to spin. Thus, freezing
    552 // a top-level worker also pauses mMainThreadDebuggeeEventTarget.
    553 class WorkerDebuggeeRunnable : public WorkerThreadRunnable {
    554 protected:
    555  explicit WorkerDebuggeeRunnable(const char* aName = "WorkerDebuggeeRunnable")
    556      : WorkerThreadRunnable(aName) {}
    557 
    558 private:
    559  // This override is deliberately private: it doesn't make sense to call it if
    560  // we know statically that we are a WorkerDebuggeeRunnable.
    561  bool IsDebuggeeRunnable() const override { return true; }
    562 };
    563 
    564 }  // namespace dom
    565 }  // namespace mozilla
    566 
    567 #endif  // mozilla_dom_workers_workerrunnable_h__