/* -*- 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/Document.h" #include "mozilla/dom/RemoteWorkerChild.h" #include "mozilla/dom/WindowGlobalChild.h" #include "mozilla/dom/WorkerCommon.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRunnable.h" namespace mozilla::dom::locks { LockManagerChild::LockManagerChild(nsIGlobalObject* aOwner) : mOwner(aOwner) { if (!NS_IsMainThread()) { mWorkerRef = IPCWorkerRef::Create(GetCurrentThreadWorkerPrivate(), "LockManagerChild"); } } void LockManagerChild::NotifyBFCacheOnMainThread(nsPIDOMWindowInner* aInner, bool aCreated) { AssertIsOnMainThread(); if (!aInner) { return; } if (aCreated) { aInner->RemoveFromBFCacheSync(); } uint32_t count = aInner->UpdateLockCount(aCreated); // It's okay for WindowGlobalChild to not exist, as it should mean it already // is destroyed and can't enter bfcache anyway. if (WindowGlobalChild* child = aInner->GetWindowGlobalChild()) { if (aCreated && count == 1) { // The first lock is active. child->BlockBFCacheFor(BFCacheStatus::ACTIVE_LOCK); } else if (count == 0) { child->UnblockBFCacheFor(BFCacheStatus::ACTIVE_LOCK); } } } class BFCacheNotifyLockRunnable final : public WorkerProxyToMainThreadRunnable { public: explicit BFCacheNotifyLockRunnable(bool aCreated) : mCreated(aCreated) {} void RunOnMainThread(WorkerPrivate* aWorkerPrivate) override { MOZ_ASSERT(aWorkerPrivate); AssertIsOnMainThread(); if (aWorkerPrivate->IsDedicatedWorker()) { LockManagerChild::NotifyBFCacheOnMainThread( aWorkerPrivate->GetAncestorWindow(), mCreated); return; } if (aWorkerPrivate->IsSharedWorker()) { aWorkerPrivate->GetRemoteWorkerController()->NotifyLock(mCreated); return; } MOZ_ASSERT_UNREACHABLE("Unexpected worker type"); } void RunBackOnWorkerThreadForCleanup(WorkerPrivate* aWorkerPrivate) override { MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); } private: bool mCreated; }; NS_IMPL_CYCLE_COLLECTION(LockManagerChild, mOwner) void LockManagerChild::RequestLock(const LockRequest& aRequest, const LockOptions& aOptions) { auto requestActor = MakeRefPtr(aRequest, aOptions.mSignal); requestActor->MaybeSetWorkerRef(); SendPLockRequestConstructor( requestActor, IPCLockRequest(nsString(aRequest.mName), aOptions.mMode, aOptions.mIfAvailable, aOptions.mSteal)); NotifyToWindow(true); } void LockManagerChild::NotifyRequestDestroy() const { NotifyToWindow(false); } void LockManagerChild::NotifyToWindow(bool aCreated) const { if (NS_IsMainThread()) { NotifyBFCacheOnMainThread(GetParentObject()->AsInnerWindow(), aCreated); return; } WorkerPrivate* wp = GetCurrentThreadWorkerPrivate(); if (wp->IsDedicatedWorker() || wp->IsSharedWorker()) { RefPtr runnable = new BFCacheNotifyLockRunnable(aCreated); runnable->Dispatch(wp); } }; } // namespace mozilla::dom::locks