Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/workers/remoteworkers/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 17 kB image not shown  

Quelle  RemoteWorkerController.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "RemoteWorkerController.h"

#include <utility>

#include "nsDebug.h"

#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Maybe.h"
#include "mozilla/RemoteLazyInputStreamStorage.h"
#include "mozilla/dom/FetchEventOpParent.h"
#include "mozilla/dom/FetchEventOpProxyParent.h"
#include "mozilla/dom/MessagePortParent.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/dom/ServiceWorkerCloneData.h"
#include "mozilla/dom/ServiceWorkerShutdownState.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "RemoteWorkerControllerParent.h"
#include "RemoteWorkerManager.h"
#include "RemoteWorkerNonLifeCycleOpControllerParent.h"
#include "RemoteWorkerParent.h"

namespace mozilla {

using namespace ipc;

namespace dom {

/* static */
already_AddRefed<RemoteWorkerController> RemoteWorkerController::Create(
    const RemoteWorkerData& aData, RemoteWorkerObserver* aObserver,
    base::ProcessId aProcessId) {
  AssertIsInMainProcess();
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(aObserver);

  RefPtr<RemoteWorkerController> controller =
      new RemoteWorkerController(aData, aObserver);

  RefPtr<RemoteWorkerManager> manager = RemoteWorkerManager::GetOrCreate();
  MOZ_ASSERT(manager);

  // XXX: We do not check for failure here, should we?
  manager->Launch(controller, aData, aProcessId);

  return controller.forget();
}

RemoteWorkerController::RemoteWorkerController(const RemoteWorkerData& aData,
                                               RemoteWorkerObserver* aObserver)
    : mObserver(aObserver),
      mState(ePending),
      mIsServiceWorker(aData.serviceWorkerData().type() ==
                       OptionalServiceWorkerData::TServiceWorkerData) {
  AssertIsInMainProcess();
  AssertIsOnBackgroundThread();
}

RemoteWorkerController::~RemoteWorkerController() {
  AssertIsOnBackgroundThread();
  MOZ_DIAGNOSTIC_ASSERT(mPendingOps.IsEmpty());
}

void RemoteWorkerController::SetWorkerActor(RemoteWorkerParent* aActor) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(!mActor);
  MOZ_ASSERT(aActor);

  mActor = aActor;
}

void RemoteWorkerController::NoteDeadWorkerActor() {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mActor);

  // The actor has been destroyed without a proper close() notification. Let's
  // inform the observer.
  if (mState == eReady) {
    mObserver->Terminated();
  }

  mActor = nullptr;

  Shutdown();
}

void RemoteWorkerController::CreationFailed() {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT(mState == ePending || mState == eTerminated);

  if (mState == eTerminated) {
    MOZ_ASSERT(!mActor);
    MOZ_ASSERT(!mNonLifeCycleOpController);
    MOZ_ASSERT(mPendingOps.IsEmpty());
    // Nothing to do.
    return;
  }

  NoteDeadWorker();

  mObserver->CreationFailed();
}

void RemoteWorkerController::CreationSucceeded() {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mState == ePending || mState == eTerminated);

  if (mState == eTerminated) {
    MOZ_ASSERT(!mActor);
    MOZ_ASSERT(!mNonLifeCycleOpController);
    MOZ_ASSERT(mPendingOps.IsEmpty());
    // Nothing to do.
    return;
  }

  MOZ_ASSERT(mActor);

  // mNonLifeCycleOpController could be already shutdown at the this moment.
  // So no need to assert its existence.
  // op->MaybeStart() will return true to ensure the op will not be in the
  // mPendingOps

  mState = eReady;

  mObserver->CreationSucceeded();

  auto pendingOps = std::move(mPendingOps);

  for (auto& op : pendingOps) {
    DebugOnly<bool> started = op->MaybeStart(this);
    MOZ_ASSERT(started);
  }
}

void RemoteWorkerController::ErrorPropagation(const ErrorValue& aValue) {
  AssertIsOnBackgroundThread();

  mObserver->ErrorReceived(aValue);
}

void RemoteWorkerController::NotifyLock(bool aCreated) {
  AssertIsOnBackgroundThread();

  mObserver->LockNotified(aCreated);
}

void RemoteWorkerController::NotifyWebTransport(bool aCreated) {
  AssertIsOnBackgroundThread();

  mObserver->WebTransportNotified(aCreated);
}

void RemoteWorkerController::WorkerTerminated() {
  AssertIsOnBackgroundThread();

  NoteDeadWorker();

  mObserver->Terminated();
}

void RemoteWorkerController::CancelAllPendingOps() {
  AssertIsOnBackgroundThread();

  auto pendingOps = std::move(mPendingOps);

  for (auto& op : pendingOps) {
    op->Cancel();
  }
}

void RemoteWorkerController::Shutdown() {
  AssertIsOnBackgroundThread();
  Unused << NS_WARN_IF(mIsServiceWorker && !mPendingOps.IsEmpty());

  if (mState == eTerminated) {
    MOZ_ASSERT(mPendingOps.IsEmpty());
    return;
  }

  mState = eTerminated;

  CancelAllPendingOps();

  if (mNonLifeCycleOpController) {
    mNonLifeCycleOpController->Shutdown();
    mNonLifeCycleOpController = nullptr;
  }

  if (!mActor) {
    return;
  }

  mActor->SetController(nullptr);

  /**
   * The "non-remote-side" of the Service Worker will have ensured that the
   * remote worker is terminated before calling `Shutdown().`
   */

  if (mIsServiceWorker) {
    mActor->MaybeSendDelete();
  } else {
    Unused << mActor->SendExecOp(SharedWorkerTerminateOpArgs());
  }

  mActor = nullptr;
}

void RemoteWorkerController::NoteDeadWorker() {
  AssertIsOnBackgroundThread();

  CancelAllPendingOps();

  /**
   * The "non-remote-side" of the Service Worker will initiate `Shutdown()`
   * once it's notified that all dispatched operations have either completed
   * or canceled. That is, it'll explicitly call `Shutdown()` later.
   */

  if (!mIsServiceWorker) {
    Shutdown();
  }
}

template <typename... Args>
void RemoteWorkerController::MaybeStartSharedWorkerOp(Args&&... aArgs) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(!mIsServiceWorker);

  UniquePtr<PendingSharedWorkerOp> op =
      MakeUnique<PendingSharedWorkerOp>(std::forward<Args>(aArgs)...);

  if (!op->MaybeStart(this)) {
    mPendingOps.AppendElement(std::move(op));
  }
}

void RemoteWorkerController::AddWindowID(uint64_t aWindowID) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(aWindowID);

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eAddWindowID, aWindowID);
}

void RemoteWorkerController::RemoveWindowID(uint64_t aWindowID) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(aWindowID);

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eRemoveWindowID, aWindowID);
}

void RemoteWorkerController::AddPortIdentifier(
    const MessagePortIdentifier& aPortIdentifier) {
  AssertIsOnBackgroundThread();

  MaybeStartSharedWorkerOp(aPortIdentifier);
}

void RemoteWorkerController::Terminate() {
  AssertIsOnBackgroundThread();

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eTerminate);
}

void RemoteWorkerController::Suspend() {
  AssertIsOnBackgroundThread();

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eSuspend);
}

void RemoteWorkerController::Resume() {
  AssertIsOnBackgroundThread();

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eResume);
}

void RemoteWorkerController::Freeze() {
  AssertIsOnBackgroundThread();

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eFreeze);
}

void RemoteWorkerController::Thaw() {
  AssertIsOnBackgroundThread();

  MaybeStartSharedWorkerOp(PendingSharedWorkerOp::eThaw);
}

RefPtr<ServiceWorkerOpPromise> RemoteWorkerController::ExecServiceWorkerOp(
    ServiceWorkerOpArgs&& aArgs) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mIsServiceWorker);

  RefPtr<ServiceWorkerOpPromise::Private> promise =
      new ServiceWorkerOpPromise::Private(__func__);

  UniquePtr<PendingServiceWorkerOp> op =
      MakeUnique<PendingServiceWorkerOp>(std::move(aArgs), promise);

  if (!op->MaybeStart(this)) {
    mPendingOps.AppendElement(std::move(op));
  }

  return promise;
}

RefPtr<ServiceWorkerFetchEventOpPromise>
RemoteWorkerController::ExecServiceWorkerFetchEventOp(
    const ParentToParentServiceWorkerFetchEventOpArgs& aArgs,
    RefPtr<FetchEventOpParent> aReal) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mIsServiceWorker);

  RefPtr<ServiceWorkerFetchEventOpPromise::Private> promise =
      new ServiceWorkerFetchEventOpPromise::Private(__func__);

  UniquePtr<PendingSWFetchEventOp> op =
      MakeUnique<PendingSWFetchEventOp>(aArgs, promise, std::move(aReal));

  if (!op->MaybeStart(this)) {
    mPendingOps.AppendElement(std::move(op));
  }

  return promise;
}

RefPtr<GenericPromise> RemoteWorkerController::SetServiceWorkerSkipWaitingFlag()
    const {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mObserver);

  RefPtr<GenericPromise::Private> promise =
      new GenericPromise::Private(__func__);

  static_cast<RemoteWorkerControllerParent*>(mObserver.get())
      ->MaybeSendSetServiceWorkerSkipWaitingFlag(
          [promise](bool aOk) { promise->Resolve(aOk, __func__); });

  return promise;
}

bool RemoteWorkerController::IsTerminated() const {
  return mState == eTerminated;
}

RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
    Type aType, uint64_t aWindowID)
    : mType(aType), mWindowID(aWindowID) {
  AssertIsOnBackgroundThread();
}

RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
    const MessagePortIdentifier& aPortIdentifier)
    : mType(ePortIdentifier), mPortIdentifier(aPortIdentifier) {
  AssertIsOnBackgroundThread();
}

RemoteWorkerController::PendingSharedWorkerOp::~PendingSharedWorkerOp() {
  AssertIsOnBackgroundThread();
  MOZ_DIAGNOSTIC_ASSERT(mCompleted);
}

bool RemoteWorkerController::PendingSharedWorkerOp::MaybeStart(
    RemoteWorkerController* const aOwner) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(!mCompleted);
  MOZ_ASSERT(aOwner);

  if (aOwner->mState == RemoteWorkerController::eTerminated) {
    Cancel();
    return true;
  }

  if (aOwner->mState == RemoteWorkerController::ePending &&
      mType != eTerminate) {
    return false;
  }

  switch (mType) {
    case eTerminate:
      aOwner->Shutdown();
      break;
    case eSuspend:
      Unused << aOwner->mActor->SendExecOp(SharedWorkerSuspendOpArgs());
      break;
    case eResume:
      Unused << aOwner->mActor->SendExecOp(SharedWorkerResumeOpArgs());
      break;
    case eFreeze:
      Unused << aOwner->mActor->SendExecOp(SharedWorkerFreezeOpArgs());
      break;
    case eThaw:
      Unused << aOwner->mActor->SendExecOp(SharedWorkerThawOpArgs());
      break;
    case ePortIdentifier:
      // mNonLifeCycleOpController can be nullptr if the Worker is in "Killing."
      // RemoteWorkerNonLifeCycleOpControllerChild switches to the Killed status
      // earlier than RemoteWorkerChild since it switches the status on the
      // worker thread, not the main thread.
      if (!aOwner->mNonLifeCycleOpController) {
        Cancel();
        return true;
      }
      if (!aOwner->mNonLifeCycleOpController->CanSend()) {
        return false;
      }
      Unused << aOwner->mNonLifeCycleOpController->SendExecOp(
          SharedWorkerPortIdentifierOpArgs(mPortIdentifier));
      break;
    case eAddWindowID:
      Unused << aOwner->mActor->SendExecOp(
          SharedWorkerAddWindowIDOpArgs(mWindowID));
      break;
    case eRemoveWindowID:
      Unused << aOwner->mActor->SendExecOp(
          SharedWorkerRemoveWindowIDOpArgs(mWindowID));
      break;
    default:
      MOZ_CRASH("Unknown op.");
  }

  mCompleted = true;

  return true;
}

void RemoteWorkerController::PendingSharedWorkerOp::Cancel() {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(!mCompleted);

  // We don't want to leak the port if the operation has not been processed.
  if (mType == ePortIdentifier) {
    MessagePortParent::ForceClose(mPortIdentifier.uuid(),
                                  mPortIdentifier.destinationUuid(),
                                  mPortIdentifier.sequenceId());
  }

  mCompleted = true;
}

RemoteWorkerController::PendingServiceWorkerOp::PendingServiceWorkerOp(
    ServiceWorkerOpArgs&& aArgs,
    RefPtr<ServiceWorkerOpPromise::Private> aPromise)
    : mArgs(std::move(aArgs)), mPromise(std::move(aPromise)) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mPromise);
}

RemoteWorkerController::PendingServiceWorkerOp::~PendingServiceWorkerOp() {
  AssertIsOnBackgroundThread();
  MOZ_DIAGNOSTIC_ASSERT(!mPromise);
}

bool RemoteWorkerController::PendingServiceWorkerOp::MaybeStart(
    RemoteWorkerController* const aOwner) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mPromise);
  MOZ_ASSERT(aOwner);

  if (NS_WARN_IF(aOwner->mState == RemoteWorkerController::eTerminated)) {
    mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
    mPromise = nullptr;
    return true;
  }

  // The target content process must still be starting up.
  if (!aOwner->mActor) {
    // We can avoid starting the worker at all if we know it should be
    // terminated.
    MOZ_ASSERT(aOwner->mState == RemoteWorkerController::ePending);
    if (mArgs.type() ==
        ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs) {
      aOwner->CancelAllPendingOps();
      Cancel();

      aOwner->mState = RemoteWorkerController::eTerminated;

      return true;
    }

    return false;
  }

  /**
   * Allow termination operations to pass through while pending because the
   * remote Service Worker can be terminated while still starting up.
   */

  if (aOwner->mState == RemoteWorkerController::ePending &&
      mArgs.type() !=
          ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs) {
    return false;
  }

  switch (mArgs.type()) {
    case ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs:
    case ServiceWorkerOpArgs::TParentToChildServiceWorkerFetchEventOpArgs: {
      MaybeReportServiceWorkerShutdownProgress(mArgs);

      aOwner->mActor->SendExecServiceWorkerOp(mArgs)->Then(
          GetCurrentSerialEventTarget(), __func__,
          [promise = std::move(mPromise)](
              PRemoteWorkerParent::ExecServiceWorkerOpPromise::
                  ResolveOrRejectValue&& aResult) {
            if (NS_WARN_IF(aResult.IsReject())) {
              promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
              return;
            }

            promise->Resolve(std::move(aResult.ResolveValue()), __func__);
          });
      break;
    }
    default: {
      // mNonLifeCycleOpController can be nullptr if the Worker is in "Killing."
      // RemoteWorkerNonLifeCycleOpControllerChild switches to the Killed status
      // earlier than RemoteWorkerChild since it switches the status on the
      // worker thread, not the main thread.
      if (!aOwner->mNonLifeCycleOpController) {
        Cancel();
        return true;
      }
      if (!aOwner->mNonLifeCycleOpController->CanSend()) {
        return false;
      }
      aOwner->mNonLifeCycleOpController->SendExecServiceWorkerOp(mArgs)->Then(
          GetCurrentSerialEventTarget(), __func__,
          [promise = std::move(mPromise)](
              PRemoteWorkerParent::ExecServiceWorkerOpPromise::
                  ResolveOrRejectValue&& aResult) {
            if (NS_WARN_IF(aResult.IsReject())) {
              promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
              return;
            }

            promise->Resolve(std::move(aResult.ResolveValue()), __func__);
          });
    }
  }
  return true;
}

void RemoteWorkerController::PendingServiceWorkerOp::Cancel() {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mPromise);

  mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
  mPromise = nullptr;
}

RemoteWorkerController::PendingSWFetchEventOp::PendingSWFetchEventOp(
    const ParentToParentServiceWorkerFetchEventOpArgs& aArgs,
    RefPtr<ServiceWorkerFetchEventOpPromise::Private> aPromise,
    RefPtr<FetchEventOpParent>&& aReal)
    : mArgs(aArgs), mPromise(std::move(aPromise)), mReal(aReal) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mPromise);

  // If there is a TParentToParentStream in the request body, we need to
  // save it to our stream.
  IPCInternalRequest& req = mArgs.common().internalRequest();
  if (req.body().isSome() &&
      req.body().ref().type() == BodyStreamVariant::TParentToParentStream) {
    nsCOMPtr<nsIInputStream> stream;
    auto streamLength = req.bodySize();
    const auto& uuid = req.body().ref().get_ParentToParentStream().uuid();

    auto storage = RemoteLazyInputStreamStorage::Get().unwrapOr(nullptr);
    MOZ_DIAGNOSTIC_ASSERT(storage);
    storage->GetStream(uuid, 0, streamLength, getter_AddRefs(mBodyStream));
    storage->ForgetStream(uuid);

    MOZ_DIAGNOSTIC_ASSERT(mBodyStream);

    req.body() = Nothing();
  }
}

RemoteWorkerController::PendingSWFetchEventOp::~PendingSWFetchEventOp() {
  AssertIsOnBackgroundThread();
  MOZ_DIAGNOSTIC_ASSERT(!mPromise);
}

bool RemoteWorkerController::PendingSWFetchEventOp::MaybeStart(
    RemoteWorkerController* const aOwner) {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mPromise);
  MOZ_ASSERT(aOwner);

  if (NS_WARN_IF(aOwner->mState == RemoteWorkerController::eTerminated)) {
    mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
    mPromise = nullptr;
    // Because the worker has transitioned to terminated, this operation is moot
    // and so we should return true because there's no need to queue it.
    return true;
  }

  // The target content process must still be starting up.
  if (!aOwner->mActor) {
    MOZ_ASSERT(aOwner->mState == RemoteWorkerController::ePending);
    return false;
  }

  // At this point we are handing off responsibility for the promise to the
  // actor.
  FetchEventOpProxyParent::Create(aOwner->mActor.get(), std::move(mPromise),
                                  mArgs, std::move(mReal),
                                  std::move(mBodyStream));

  return true;
}

void RemoteWorkerController::PendingSWFetchEventOp::Cancel() {
  AssertIsOnBackgroundThread();
  MOZ_ASSERT(mPromise);

  if (mPromise) {
    mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
    mPromise = nullptr;
  }
}

}  // namespace dom
}  // namespace mozilla

Messung V0.5
C=95 H=98 G=96

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.