tor-browser

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

LockRequestChild.cpp (3976B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "LockRequestChild.h"
      8 
      9 #include "LockManagerChild.h"
     10 #include "mozilla/dom/Promise.h"
     11 #include "mozilla/dom/WorkerPrivate.h"
     12 
     13 namespace mozilla::dom::locks {
     14 
     15 using IPCResult = mozilla::ipc::IPCResult;
     16 
     17 NS_IMPL_ISUPPORTS(LockRequestChild, nsISupports)
     18 
     19 MOZ_CAN_RUN_SCRIPT static void RunCallbackAndSettlePromise(
     20    LockGrantedCallback& aCallback, mozilla::dom::Lock* lock,
     21    Promise& aPromise) {
     22  ErrorResult rv;
     23  if (RefPtr<Promise> result = aCallback.Call(
     24          lock, rv, nullptr, CallbackObject::eRethrowExceptions)) {
     25    aPromise.MaybeResolve(result);
     26  } else if (rv.Failed() && !rv.IsUncatchableException()) {
     27    aPromise.MaybeReject(std::move(rv));
     28    return;
     29  } else {
     30    aPromise.MaybeResolveWithUndefined();
     31  }
     32  // This is required even with no failure. IgnoredErrorResult is not an option
     33  // since MaybeReject does not accept it.
     34  rv.WouldReportJSException();
     35  if (NS_WARN_IF(rv.IsUncatchableException())) {
     36    rv.SuppressException();  // XXX: Why does this happen anyway?
     37  }
     38  MOZ_ASSERT(!rv.Failed());
     39 }
     40 
     41 LockRequestChild::LockRequestChild(
     42    const LockRequest& aRequest,
     43    const Optional<OwningNonNull<AbortSignal>>& aSignal)
     44    : mRequest(aRequest) {
     45  if (aSignal.WasPassed()) {
     46    Follow(&aSignal.Value());
     47  }
     48 }
     49 
     50 void LockRequestChild::MaybeSetWorkerRef() {
     51  if (!NS_IsMainThread()) {
     52    mWorkerRef = StrongWorkerRef::Create(
     53        GetCurrentThreadWorkerPrivate(), "LockManager",
     54        [self = RefPtr(this)]() { self->mWorkerRef = nullptr; });
     55  }
     56 }
     57 
     58 void LockRequestChild::ActorDestroy(ActorDestroyReason aReason) {
     59  CastedManager()->NotifyRequestDestroy();
     60 }
     61 
     62 IPCResult LockRequestChild::RecvResolve(const LockMode& aLockMode,
     63                                        bool aIsAvailable) {
     64  Unfollow();
     65 
     66  RefPtr<Lock> lock;
     67  RefPtr<Promise> promise;
     68  if (aIsAvailable) {
     69    IgnoredErrorResult err;
     70    lock = new Lock(CastedManager()->GetParentObject(), this, mRequest.mName,
     71                    aLockMode, mRequest.mPromise, err);
     72    if (MOZ_UNLIKELY(err.Failed())) {
     73      mRequest.mPromise->MaybeRejectWithUnknownError(
     74          "Failed to allocate a lock");
     75      return IPC_OK();
     76    }
     77    lock->GetWaitingPromise().AppendNativeHandler(lock);
     78    promise = &lock->GetWaitingPromise();
     79  } else {
     80    // We are in `ifAvailable: true` mode and the lock is not available.
     81    // There is no waitingPromise since there is no lock, so settle the promise
     82    // from the request instead.
     83    // This matches "If ifAvailable is true and request is not grantable" step.
     84    promise = mRequest.mPromise;
     85  }
     86 
     87  // XXX(krosylight): MOZ_KnownLive shouldn't be needed here, mRequest is const
     88  RunCallbackAndSettlePromise(MOZ_KnownLive(*mRequest.mCallback), lock,
     89                              *promise);
     90  return IPC_OK();
     91 }
     92 
     93 IPCResult LockRequestChild::Recv__delete__(bool aAborted) {
     94  MOZ_ASSERT(aAborted, "__delete__ is currently only for abort");
     95  Unfollow();
     96  mRequest.mPromise->MaybeRejectWithAbortError("The lock request is aborted");
     97  return IPC_OK();
     98 }
     99 
    100 void LockRequestChild::RunAbortAlgorithm() {
    101  AutoJSAPI jsapi;
    102  if (NS_WARN_IF(
    103          !jsapi.Init(static_cast<AbortSignal*>(Signal())->GetOwnerGlobal()))) {
    104    mRequest.mPromise->MaybeRejectWithAbortError("The lock request is aborted");
    105  } else {
    106    JSContext* cx = jsapi.cx();
    107    JS::Rooted<JS::Value> reason(cx);
    108    Signal()->GetReason(cx, &reason);
    109    mRequest.mPromise->MaybeReject(reason);
    110  }
    111 
    112  Unfollow();
    113  Send__delete__(this, true);
    114 }
    115 
    116 inline LockManagerChild* LockRequestChild::CastedManager() const {
    117  return static_cast<LockManagerChild*>(Manager());
    118 };
    119 
    120 }  // namespace mozilla::dom::locks