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