summaryrefslogtreecommitdiffstats
path: root/dom/locks/LockRequestChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/locks/LockRequestChild.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/dom/locks/LockRequestChild.cpp b/dom/locks/LockRequestChild.cpp
new file mode 100644
index 0000000000..51731c5eed
--- /dev/null
+++ b/dom/locks/LockRequestChild.cpp
@@ -0,0 +1,120 @@
+/* -*- 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 "LockManagerChild.h"
+#include "LockRequestChild.h"
+
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/WorkerPrivate.h"
+
+namespace mozilla::dom::locks {
+
+using IPCResult = mozilla::ipc::IPCResult;
+
+NS_IMPL_ISUPPORTS(LockRequestChild, nsISupports)
+
+MOZ_CAN_RUN_SCRIPT static void RunCallbackAndSettlePromise(
+ LockGrantedCallback& aCallback, mozilla::dom::Lock* lock,
+ Promise& aPromise) {
+ ErrorResult rv;
+ if (RefPtr<Promise> result = aCallback.Call(
+ lock, rv, nullptr, CallbackObject::eRethrowExceptions)) {
+ aPromise.MaybeResolve(result);
+ } else if (rv.Failed() && !rv.IsUncatchableException()) {
+ aPromise.MaybeReject(std::move(rv));
+ return;
+ } else {
+ aPromise.MaybeResolveWithUndefined();
+ }
+ // This is required even with no failure. IgnoredErrorResult is not an option
+ // since MaybeReject does not accept it.
+ rv.WouldReportJSException();
+ if (NS_WARN_IF(rv.IsUncatchableException())) {
+ rv.SuppressException(); // XXX: Why does this happen anyway?
+ }
+ MOZ_ASSERT(!rv.Failed());
+}
+
+LockRequestChild::LockRequestChild(
+ const LockRequest& aRequest,
+ const Optional<OwningNonNull<AbortSignal>>& aSignal)
+ : mRequest(aRequest) {
+ if (aSignal.WasPassed()) {
+ Follow(&aSignal.Value());
+ }
+}
+
+void LockRequestChild::MaybeSetWorkerRef() {
+ if (!NS_IsMainThread()) {
+ mWorkerRef = StrongWorkerRef::Create(
+ GetCurrentThreadWorkerPrivate(), "LockManager",
+ [self = RefPtr(this)]() { self->mWorkerRef = nullptr; });
+ }
+}
+
+void LockRequestChild::ActorDestroy(ActorDestroyReason aReason) {
+ CastedManager()->NotifyRequestDestroy();
+}
+
+IPCResult LockRequestChild::RecvResolve(const LockMode& aLockMode,
+ bool aIsAvailable) {
+ Unfollow();
+
+ RefPtr<Lock> lock;
+ RefPtr<Promise> promise;
+ if (aIsAvailable) {
+ IgnoredErrorResult err;
+ lock = new Lock(CastedManager()->GetParentObject(), this, mRequest.mName,
+ aLockMode, mRequest.mPromise, err);
+ if (MOZ_UNLIKELY(err.Failed())) {
+ mRequest.mPromise->MaybeRejectWithUnknownError(
+ "Failed to allocate a lock");
+ return IPC_OK();
+ }
+ lock->GetWaitingPromise().AppendNativeHandler(lock);
+ promise = &lock->GetWaitingPromise();
+ } else {
+ // We are in `ifAvailable: true` mode and the lock is not available.
+ // There is no waitingPromise since there is no lock, so settle the promise
+ // from the request instead.
+ // This matches "If ifAvailable is true and request is not grantable" step.
+ promise = mRequest.mPromise;
+ }
+
+ // XXX(krosylight): MOZ_KnownLive shouldn't be needed here, mRequest is const
+ RunCallbackAndSettlePromise(MOZ_KnownLive(*mRequest.mCallback), lock,
+ *promise);
+ return IPC_OK();
+}
+
+IPCResult LockRequestChild::Recv__delete__(bool aAborted) {
+ MOZ_ASSERT(aAborted, "__delete__ is currently only for abort");
+ Unfollow();
+ mRequest.mPromise->MaybeRejectWithAbortError("The lock request is aborted");
+ return IPC_OK();
+}
+
+void LockRequestChild::RunAbortAlgorithm() {
+ AutoJSAPI jsapi;
+ if (NS_WARN_IF(
+ !jsapi.Init(static_cast<AbortSignal*>(Signal())->GetOwnerGlobal()))) {
+ mRequest.mPromise->MaybeRejectWithAbortError("The lock request is aborted");
+ } else {
+ JSContext* cx = jsapi.cx();
+ JS::Rooted<JS::Value> reason(cx);
+ Signal()->GetReason(cx, &reason);
+ mRequest.mPromise->MaybeReject(reason);
+ }
+
+ Unfollow();
+ Send__delete__(this, true);
+}
+
+inline LockManagerChild* LockRequestChild::CastedManager() const {
+ return static_cast<LockManagerChild*>(Manager());
+};
+
+} // namespace mozilla::dom::locks