tor-browser

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

SharedWorkerOp.cpp (7674B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "SharedWorkerOp.h"
      6 
      7 #include "mozilla/dom/MessagePort.h"
      8 #include "mozilla/dom/RemoteWorkerChild.h"
      9 #include "mozilla/dom/RemoteWorkerNonLifeCycleOpControllerChild.h"
     10 #include "mozilla/dom/WorkerPrivate.h"
     11 #include "mozilla/dom/WorkerRunnable.h"
     12 #include "mozilla/dom/WorkerScope.h"
     13 
     14 namespace mozilla::dom {
     15 
     16 using remoteworker::Canceled;
     17 using remoteworker::Killed;
     18 using remoteworker::Pending;
     19 using remoteworker::Running;
     20 
     21 namespace {
     22 
     23 // Normal runnable because AddPortIdentifier() is going to exec JS code.
     24 class MessagePortIdentifierRunnable final : public WorkerSameThreadRunnable {
     25 public:
     26  MessagePortIdentifierRunnable(
     27      RemoteWorkerNonLifeCycleOpControllerChild* aActor,
     28      const MessagePortIdentifier& aPortIdentifier)
     29      : WorkerSameThreadRunnable("MessagePortIdentifierRunnable"),
     30        mActor(aActor),
     31        mPortIdentifier(aPortIdentifier) {}
     32 
     33 private:
     34  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
     35    if (aWorkerPrivate->GlobalScope()->IsDying()) {
     36      mPortIdentifier.ForceClose();
     37      return true;
     38    }
     39    if (!aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier)) {
     40      mActor->ErrorPropagation(NS_ERROR_FAILURE);
     41    }
     42    return true;
     43  }
     44 
     45  RefPtr<RemoteWorkerNonLifeCycleOpControllerChild> mActor;
     46  UniqueMessagePortId mPortIdentifier;
     47 };
     48 
     49 class UpdateWindowIDRunnable final : public WorkerThreadRunnable {
     50 public:
     51  UpdateWindowIDRunnable(const uint64_t& aWindowID, const bool& aIsAdd)
     52      : WorkerThreadRunnable("UpdateWindowIDRunnable"),
     53        mWindowID(aWindowID),
     54        mIsAdd(aIsAdd) {}
     55 
     56 private:
     57  bool PreDispatch(WorkerPrivate* aWorkerPrivate) final { return true; }
     58  void PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) final {
     59  }
     60 
     61  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
     62    aWorkerPrivate->UpdateWindowIDToDebugger(mWindowID, mIsAdd);
     63    return true;
     64  }
     65 
     66  uint64_t mWindowID;
     67  bool mIsAdd;
     68 };
     69 
     70 }  // namespace
     71 
     72 SharedWorkerOp::SharedWorkerOp(SharedWorkerOpArgs&& aArgs)
     73    : mOpArgs(std::move(aArgs)) {}
     74 
     75 SharedWorkerOp::~SharedWorkerOp() { MOZ_ASSERT(mStarted); }
     76 
     77 void SharedWorkerOp::Cancel() {
     78 #ifdef DEBUG
     79  mStarted = true;
     80 #endif
     81 }
     82 
     83 bool SharedWorkerOp::MaybeStart(RemoteWorkerChild* aOwner,
     84                                RemoteWorkerState& aState) {
     85  MOZ_ASSERT(!mStarted);
     86  MOZ_ASSERT(aOwner);
     87  // Thread: We are on the Worker Launcher thread.
     88 
     89  // Return false, indicating we should queue this op if our current state is
     90  // pending and this isn't a termination op (which should skip the line).
     91  if (aState.is<Pending>() && !IsTerminationOp()) {
     92    return false;
     93  }
     94 
     95  // If the worker is already shutting down (which should be unexpected
     96  // because we should be told new operations after a termination op), just
     97  // return true to indicate the op should be discarded.
     98  if (aState.is<Canceled>() || aState.is<Killed>()) {
     99 #ifdef DEBUG
    100    mStarted = true;
    101 #endif
    102    return true;
    103  }
    104 
    105  MOZ_ASSERT(aState.is<Running>() || IsTerminationOp());
    106 
    107  if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerThawOpArgs) {
    108    aOwner->SetIsThawing(true);
    109  }
    110 
    111  RefPtr<SharedWorkerOp> self = this;
    112  RefPtr<RemoteWorkerChild> owner = aOwner;
    113 
    114  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    115      __func__, [self = std::move(self), owner = std::move(owner)]() mutable {
    116        {
    117          auto lock = owner->mState.Lock();
    118 
    119          if (NS_WARN_IF(lock->is<Canceled>() || lock->is<Killed>())) {
    120            self->Cancel();
    121            return;
    122          }
    123        }
    124 
    125        self->StartOnMainThread(owner);
    126        if (self->mOpArgs.type() ==
    127            SharedWorkerOpArgs::TSharedWorkerThawOpArgs) {
    128          owner->SetIsThawing(false);
    129          owner->RunAllPendingOpsOnMainThread();
    130        }
    131      });
    132 
    133  MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
    134 
    135 #ifdef DEBUG
    136  mStarted = true;
    137 #endif
    138 
    139  return true;
    140 }
    141 
    142 void SharedWorkerOp::StartOnMainThread(RefPtr<RemoteWorkerChild>& aOwner) {
    143  AssertIsOnMainThread();
    144 
    145  if (IsTerminationOp()) {
    146    aOwner->CloseWorkerOnMainThread();
    147    return;
    148  }
    149 
    150  auto lock = aOwner->mState.Lock();
    151  MOZ_ASSERT(lock->is<Running>());
    152  if (!lock->is<Running>()) {
    153    aOwner->ErrorPropagationDispatch(NS_ERROR_DOM_INVALID_STATE_ERR);
    154    return;
    155  }
    156 
    157  RefPtr<WorkerPrivate> workerPrivate = lock->as<Running>().mWorkerPrivate;
    158 
    159  MOZ_ASSERT(workerPrivate);
    160 
    161  if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerSuspendOpArgs) {
    162    workerPrivate->ParentWindowPaused();
    163  } else if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerResumeOpArgs) {
    164    workerPrivate->ParentWindowResumed();
    165  } else if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerFreezeOpArgs) {
    166    workerPrivate->Freeze(nullptr);
    167  } else if (mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerThawOpArgs) {
    168    workerPrivate->Thaw(nullptr);
    169  } else if (mOpArgs.type() ==
    170             SharedWorkerOpArgs::TSharedWorkerPortIdentifierOpArgs) {
    171    MOZ_CRASH(
    172        "PortIdentifierOpArgs should not be processed by "
    173        "StartOnMainThread!!!");
    174  } else if (mOpArgs.type() ==
    175             SharedWorkerOpArgs::TSharedWorkerAddWindowIDOpArgs) {
    176    aOwner->mWindowIDs.AppendElement(
    177        mOpArgs.get_SharedWorkerAddWindowIDOpArgs().windowID());
    178    RefPtr<UpdateWindowIDRunnable> r = new UpdateWindowIDRunnable(
    179        mOpArgs.get_SharedWorkerAddWindowIDOpArgs().windowID(), true);
    180    (void)r->Dispatch(workerPrivate);
    181  } else if (mOpArgs.type() ==
    182             SharedWorkerOpArgs::TSharedWorkerRemoveWindowIDOpArgs) {
    183    aOwner->mWindowIDs.RemoveElement(
    184        mOpArgs.get_SharedWorkerRemoveWindowIDOpArgs().windowID());
    185    RefPtr<UpdateWindowIDRunnable> r = new UpdateWindowIDRunnable(
    186        mOpArgs.get_SharedWorkerRemoveWindowIDOpArgs().windowID(), false);
    187    (void)r->Dispatch(workerPrivate);
    188  } else {
    189    MOZ_CRASH("Unknown SharedWorkerOpArgs type!");
    190  }
    191 
    192 #ifdef DEBUG
    193  if (!mStarted) {
    194    mStarted = true;
    195  }
    196 #endif
    197 }
    198 
    199 void SharedWorkerOp::Start(RemoteWorkerNonLifeCycleOpControllerChild* aOwner,
    200                           RemoteWorkerState& aState) {
    201  MOZ_ASSERT(!mStarted);
    202  MOZ_ASSERT(aOwner);
    203  // Thread: We are on the Worker thread.
    204 
    205  // Only PortIdentifierOp is NonLifeCycle related opertaion.
    206  MOZ_ASSERT(mOpArgs.type() ==
    207             SharedWorkerOpArgs::TSharedWorkerPortIdentifierOpArgs);
    208 
    209  // Should never be Pending state.
    210  MOZ_ASSERT(!aState.is<Pending>());
    211 
    212  // If the worker is already shutting down (which should be unexpected
    213  // because we should be told new operations after a termination op), just
    214  // return directly.
    215  if (aState.is<Canceled>() || aState.is<Killed>()) {
    216 #ifdef DEBUG
    217    mStarted = true;
    218 #endif
    219    MessagePort::ForceClose(
    220        mOpArgs.get_SharedWorkerPortIdentifierOpArgs().portIdentifier());
    221    return;
    222  }
    223 
    224  MOZ_ASSERT(aState.is<Running>());
    225 
    226  // RefPtr<WorkerPrivate> workerPrivate = aState.as<Running>().mWorkerPrivate;
    227  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    228 
    229  RefPtr<MessagePortIdentifierRunnable> r = new MessagePortIdentifierRunnable(
    230      aOwner, mOpArgs.get_SharedWorkerPortIdentifierOpArgs().portIdentifier());
    231 
    232  if (NS_WARN_IF(!r->Dispatch(workerPrivate))) {
    233    aOwner->ErrorPropagation(NS_ERROR_FAILURE);
    234  }
    235 
    236 #ifdef DEBUG
    237  mStarted = true;
    238 #endif
    239 }
    240 
    241 bool SharedWorkerOp::IsTerminationOp() const {
    242  return mOpArgs.type() == SharedWorkerOpArgs::TSharedWorkerTerminateOpArgs;
    243 }
    244 
    245 }  // namespace mozilla::dom