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/. */
7 #include "LockManagerChild.h"
8 #include "LockRequestChild.h"
10 #include "mozilla/dom/Promise.h"
11 #include "mozilla/dom/WorkerPrivate.h"
13 namespace mozilla::dom::locks
{
15 using IPCResult
= mozilla::ipc::IPCResult
;
17 NS_IMPL_ISUPPORTS(LockRequestChild
, nsISupports
)
19 MOZ_CAN_RUN_SCRIPT
static void RunCallbackAndSettlePromise(
20 LockGrantedCallback
& aCallback
, mozilla::dom::Lock
* lock
,
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
));
30 aPromise
.MaybeResolveWithUndefined();
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?
38 MOZ_ASSERT(!rv
.Failed());
41 LockRequestChild::LockRequestChild(
42 const LockRequest
& aRequest
,
43 const Optional
<OwningNonNull
<AbortSignal
>>& aSignal
)
44 : mRequest(aRequest
) {
45 if (aSignal
.WasPassed()) {
46 Follow(&aSignal
.Value());
50 void LockRequestChild::MaybeSetWorkerRef() {
51 if (!NS_IsMainThread()) {
52 mWorkerRef
= StrongWorkerRef::Create(
53 GetCurrentThreadWorkerPrivate(), "LockManager",
54 [self
= RefPtr(this)]() { self
->mWorkerRef
= nullptr; });
58 void LockRequestChild::ActorDestroy(ActorDestroyReason aReason
) {
59 CastedManager()->NotifyRequestDestroy();
62 IPCResult
LockRequestChild::RecvResolve(const LockMode
& aLockMode
,
67 RefPtr
<Promise
> promise
;
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");
77 lock
->GetWaitingPromise().AppendNativeHandler(lock
);
78 promise
= &lock
->GetWaitingPromise();
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
;
87 // XXX(krosylight): MOZ_KnownLive shouldn't be needed here, mRequest is const
88 RunCallbackAndSettlePromise(MOZ_KnownLive(*mRequest
.mCallback
), lock
,
93 IPCResult
LockRequestChild::Recv__delete__(bool aAborted
) {
94 MOZ_ASSERT(aAborted
, "__delete__ is currently only for abort");
96 mRequest
.mPromise
->MaybeRejectWithAbortError("The lock request is aborted");
100 void LockRequestChild::RunAbortAlgorithm() {
103 !jsapi
.Init(static_cast<AbortSignal
*>(Signal())->GetOwnerGlobal()))) {
104 mRequest
.mPromise
->MaybeRejectWithAbortError("The lock request is aborted");
106 JSContext
* cx
= jsapi
.cx();
107 JS::Rooted
<JS::Value
> reason(cx
);
108 Signal()->GetReason(cx
, &reason
);
109 mRequest
.mPromise
->MaybeReject(reason
);
113 Send__delete__(this, true);
116 inline LockManagerChild
* LockRequestChild::CastedManager() const {
117 return static_cast<LockManagerChild
*>(Manager());
120 } // namespace mozilla::dom::locks