tor-browser

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

WorkerEventTarget.cpp (8138B)


      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 #include "WorkerEventTarget.h"
      8 
      9 #include "WorkerPrivate.h"
     10 #include "WorkerRunnable.h"
     11 #include "mozilla/Logging.h"
     12 #include "mozilla/dom/ReferrerInfo.h"
     13 
     14 namespace mozilla::dom {
     15 
     16 static mozilla::LazyLogModule sWorkerEventTargetLog("WorkerEventTarget");
     17 
     18 #ifdef LOG
     19 #  undef LOG
     20 #endif
     21 #ifdef LOGV
     22 #  undef LOGV
     23 #endif
     24 #define LOG(args) MOZ_LOG(sWorkerEventTargetLog, LogLevel::Debug, args);
     25 #define LOGV(args) MOZ_LOG(sWorkerEventTargetLog, LogLevel::Verbose, args);
     26 
     27 namespace {
     28 
     29 class WrappedControlRunnable final : public WorkerControlRunnable {
     30  nsCOMPtr<nsIRunnable> mInner;
     31 
     32  ~WrappedControlRunnable() = default;
     33 
     34 public:
     35  WrappedControlRunnable(WorkerPrivate* aWorkerPrivate,
     36                         nsCOMPtr<nsIRunnable>&& aInner)
     37      : WorkerControlRunnable("WrappedControlRunnable"),
     38        mInner(std::move(aInner)) {}
     39 
     40  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
     41    // Silence bad assertions, this can be dispatched from any thread.
     42    return true;
     43  }
     44 
     45  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
     46                            bool aDispatchResult) override {
     47    // Silence bad assertions, this can be dispatched from any thread.
     48  }
     49 
     50  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
     51    mInner->Run();
     52    return true;
     53  }
     54 
     55  nsresult Cancel() override {
     56    nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mInner);
     57 
     58    // If the inner runnable is not cancellable, then just do the normal
     59    // WorkerControlRunnable thing.  This will end up calling Run().
     60    if (!cr) {
     61      return Run();
     62    }
     63 
     64    // Otherwise call the inner runnable's Cancel() and treat this like
     65    // a WorkerRunnable cancel.  We can't call WorkerControlRunnable::Cancel()
     66    // in this case since that would result in both Run() and the inner
     67    // Cancel() being called.
     68    return cr->Cancel();
     69  }
     70 
     71 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
     72  NS_IMETHOD GetName(nsACString& aName) override {
     73    aName.AssignLiteral("WrappedControlRunnable(");
     74    if (nsCOMPtr<nsINamed> named = do_QueryInterface(mInner)) {
     75      nsAutoCString containedName;
     76      named->GetName(containedName);
     77      aName.Append(containedName);
     78    } else {
     79      aName.AppendLiteral("?");
     80    }
     81    aName.AppendLiteral(")");
     82    return NS_OK;
     83  }
     84 #endif
     85 };
     86 
     87 class WrappedDebuggerRunnable final : public WorkerDebuggerRunnable {
     88  nsCOMPtr<nsIRunnable> mInner;
     89 
     90  ~WrappedDebuggerRunnable() = default;
     91 
     92 public:
     93  WrappedDebuggerRunnable(WorkerPrivate* aWorkerPrivate,
     94                          nsCOMPtr<nsIRunnable>&& aInner)
     95      : WorkerDebuggerRunnable("WrappedDebuggerRunnable"),
     96        mInner(std::move(aInner)) {}
     97 
     98  virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
     99    // Silence bad assertions, this can be dispatched from any thread.
    100    return true;
    101  }
    102 
    103  virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
    104                            bool aDispatchResult) override {
    105    // Silence bad assertions, this can be dispatched from any thread.
    106  }
    107 
    108  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
    109    mInner->Run();
    110    return true;
    111  }
    112 
    113 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
    114  NS_IMETHOD GetName(nsACString& aName) override {
    115    aName.AssignLiteral("WrappedDebuggerRunnable(");
    116    if (nsCOMPtr<nsINamed> named = do_QueryInterface(mInner)) {
    117      nsAutoCString containedName;
    118      named->GetName(containedName);
    119      aName.Append(containedName);
    120    } else {
    121      aName.AppendLiteral("?");
    122    }
    123    aName.AppendLiteral(")");
    124    return NS_OK;
    125  }
    126 #endif
    127 };
    128 
    129 }  // anonymous namespace
    130 
    131 NS_IMPL_ISUPPORTS(WorkerEventTarget, nsIEventTarget, nsISerialEventTarget)
    132 
    133 WorkerEventTarget::WorkerEventTarget(WorkerPrivate* aWorkerPrivate,
    134                                     Behavior aBehavior)
    135    : mMutex("WorkerEventTarget"),
    136      mWorkerPrivate(aWorkerPrivate),
    137      mBehavior(aBehavior) {
    138  LOG(("WorkerEventTarget::WorkerEventTarget [%p] aBehavior: %u", this,
    139       (uint8_t)aBehavior));
    140  MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate);
    141 }
    142 
    143 void WorkerEventTarget::ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate) {
    144  LOG(("WorkerEventTarget::ForgetWorkerPrivate [%p] aWorkerPrivate: %p", this,
    145       aWorkerPrivate));
    146  MutexAutoLock lock(mMutex);
    147  MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate || mWorkerPrivate == aWorkerPrivate);
    148  mWorkerPrivate = nullptr;
    149 }
    150 
    151 NS_IMETHODIMP
    152 WorkerEventTarget::DispatchFromScript(nsIRunnable* aRunnable,
    153                                      DispatchFlags aFlags) {
    154  LOGV(("WorkerEventTarget::DispatchFromScript [%p] aRunnable: %p", this,
    155        aRunnable));
    156  return Dispatch(do_AddRef(aRunnable), aFlags);
    157 }
    158 
    159 NS_IMETHODIMP
    160 WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
    161                            DispatchFlags aFlags) {
    162  // NOTE: This dispatch implementation does not leak even if
    163  // `NS_DISPATCH_FALLIBLE` is not set.
    164  nsCOMPtr<nsIRunnable> runnable(aRunnable);
    165  LOGV(
    166      ("WorkerEventTarget::Dispatch [%p] aRunnable: %p", this, runnable.get()));
    167 
    168  MutexAutoLock lock(mMutex);
    169 
    170  if (!mWorkerPrivate) {
    171    return NS_ERROR_FAILURE;
    172  }
    173 
    174  if (mBehavior == Behavior::DebuggerOnly) {
    175    RefPtr<WorkerDebuggerRunnable> r =
    176        new WrappedDebuggerRunnable(mWorkerPrivate, std::move(runnable));
    177    LOGV(
    178        ("WorkerEventTarget::Dispatch [%p] Wrapped runnable as debugger "
    179         "runnable(%p)",
    180         this, r.get()));
    181    if (!r->Dispatch(mWorkerPrivate)) {
    182      LOGV(
    183          ("WorkerEventTarget::Dispatch [%p] Dispatch as debugger runnable(%p) "
    184           "fail",
    185           this, r.get()));
    186      return NS_ERROR_FAILURE;
    187    }
    188    return NS_OK;
    189  }
    190 
    191  if (mBehavior == Behavior::Hybrid) {
    192    LOGV(("WorkerEventTarget::Dispatch [%p] Dispatch as normal runnable(%p)",
    193          this, runnable.get()));
    194 
    195    RefPtr<WorkerRunnable> r =
    196        mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
    197    if (r->Dispatch(mWorkerPrivate)) {
    198      return NS_OK;
    199    }
    200    runnable = std::move(r);
    201    LOGV((
    202        "WorkerEventTarget::Dispatch [%p] Dispatch as normal runnable(%p) fail",
    203        this, runnable.get()));
    204  }
    205 
    206  RefPtr<WorkerControlRunnable> r =
    207      new WrappedControlRunnable(mWorkerPrivate, std::move(runnable));
    208  LOGV(
    209      ("WorkerEventTarget::Dispatch [%p] Wrapped runnable as control "
    210       "runnable(%p)",
    211       this, r.get()));
    212  if (!r->Dispatch(mWorkerPrivate)) {
    213    LOGV(
    214        ("WorkerEventTarget::Dispatch [%p] Dispatch as control runnable(%p) "
    215         "fail",
    216         this, r.get()));
    217    return NS_ERROR_FAILURE;
    218  }
    219 
    220  return NS_OK;
    221 }
    222 
    223 NS_IMETHODIMP
    224 WorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) {
    225  return NS_ERROR_NOT_IMPLEMENTED;
    226 }
    227 
    228 NS_IMETHODIMP
    229 WorkerEventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) {
    230  NS_ENSURE_ARG(aTask);
    231 
    232  MutexAutoLock lock(mMutex);
    233 
    234  // If mWorkerPrivate is gone, the event target is already late during
    235  // shutdown, return NS_ERROR_UNEXPECTED as documented in `nsIEventTarget.idl`.
    236  if (!mWorkerPrivate) {
    237    return NS_ERROR_UNEXPECTED;
    238  }
    239 
    240  return mWorkerPrivate->RegisterShutdownTask(aTask);
    241 }
    242 
    243 NS_IMETHODIMP
    244 WorkerEventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) {
    245  NS_ENSURE_ARG(aTask);
    246 
    247  MutexAutoLock lock(mMutex);
    248 
    249  if (!mWorkerPrivate) {
    250    return NS_ERROR_UNEXPECTED;
    251  }
    252 
    253  return mWorkerPrivate->UnregisterShutdownTask(aTask);
    254 }
    255 
    256 NS_IMETHODIMP_(bool)
    257 WorkerEventTarget::IsOnCurrentThreadInfallible() {
    258  MutexAutoLock lock(mMutex);
    259 
    260  if (!mWorkerPrivate) {
    261    return false;
    262  }
    263 
    264  return mWorkerPrivate->IsOnCurrentThread();
    265 }
    266 
    267 NS_IMETHODIMP
    268 WorkerEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) {
    269  MOZ_ASSERT(aIsOnCurrentThread);
    270  *aIsOnCurrentThread = IsOnCurrentThreadInfallible();
    271  return NS_OK;
    272 }
    273 
    274 }  // namespace mozilla::dom