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 "LockManagerParent.h"
8 #include "LockRequestParent.h"
10 #include "mozilla/PrincipalHashKey.h"
11 #include "mozilla/RefPtr.h"
12 #include "mozilla/StaticPtr.h"
13 #include "mozilla/dom/locks/PLockManager.h"
14 #include "mozilla/media/MediaUtils.h"
15 #include "nsIDUtils.h"
16 #include "nsTHashMap.h"
18 namespace mozilla::dom::locks
{
20 static StaticAutoPtr
<nsTHashMap
<PrincipalHashKey
, WeakPtr
<ManagedLocks
>>>
23 using IPCResult
= mozilla::ipc::IPCResult
;
25 LockManagerParent::LockManagerParent(NotNull
<nsIPrincipal
*> aPrincipal
,
26 const nsID
& aClientId
)
27 : mClientId(NSID_TrimBracketsUTF16(aClientId
)), mPrincipal(aPrincipal
) {
28 if (!sManagedLocksMap
) {
30 new nsTHashMap
<PrincipalHashKey
, WeakPtr
<ManagedLocks
>>();
32 mManagedLocks
= sManagedLocksMap
->Get(aPrincipal
);
36 mManagedLocks
= new ManagedLocks();
37 sManagedLocksMap
->LookupOrInsert(aPrincipal
, mManagedLocks
);
41 void LockManagerParent::ActorDestroy(ActorDestroyReason aWhy
) {
46 nsTArray
<nsString
> affectedResourceNames
;
48 mManagedLocks
->mHeldLocks
.RemoveElementsBy(
49 [this, &affectedResourceNames
](const RefPtr
<LockRequestParent
>& request
) {
50 bool equals
= request
->Manager() == this;
52 affectedResourceNames
.AppendElement(request
->Data().name());
57 for (auto& queue
: mManagedLocks
->mQueueMap
) {
58 queue
.GetModifiableData()->RemoveElementsBy(
59 [this, &name
= queue
.GetKey(),
60 &affectedResourceNames
](const RefPtr
<LockRequestParent
>& request
) {
61 bool equals
= request
->Manager() == this;
63 affectedResourceNames
.AppendElement(name
);
69 for (const nsString
& name
: affectedResourceNames
) {
70 if (auto queue
= mManagedLocks
->mQueueMap
.Lookup(name
)) {
71 ProcessRequestQueue(queue
.Data());
75 mManagedLocks
= nullptr;
76 // We just decreased the refcount and potentially deleted it, so check whether
77 // the weak pointer still points to anything and remove the entry if not.
78 if (!sManagedLocksMap
->Get(mPrincipal
)) {
79 sManagedLocksMap
->Remove(mPrincipal
);
83 void LockManagerParent::ProcessRequestQueue(
84 nsTArray
<RefPtr
<LockRequestParent
>>& aQueue
) {
85 while (aQueue
.Length()) {
86 RefPtr
<LockRequestParent
> first
= aQueue
[0];
87 if (!IsGrantableRequest(first
->Data())) {
90 aQueue
.RemoveElementAt(0);
91 mManagedLocks
->mHeldLocks
.AppendElement(first
);
92 Unused
<< NS_WARN_IF(!first
->SendResolve(first
->Data().lockMode(), true));
96 bool LockManagerParent::IsGrantableRequest(const IPCLockRequest
& aRequest
) {
97 for (const auto& held
: mManagedLocks
->mHeldLocks
) {
98 if (held
->Data().name() == aRequest
.name()) {
99 if (aRequest
.lockMode() == LockMode::Exclusive
) {
102 MOZ_ASSERT(aRequest
.lockMode() == LockMode::Shared
);
103 if (held
->Data().lockMode() == LockMode::Exclusive
) {
111 IPCResult
LockManagerParent::RecvQuery(QueryResolver
&& aResolver
) {
112 LockManagerSnapshot snapshot
;
113 snapshot
.mHeld
.Construct();
114 snapshot
.mPending
.Construct();
115 for (const auto& queueMapEntry
: mManagedLocks
->mQueueMap
) {
116 for (const RefPtr
<LockRequestParent
>& request
: queueMapEntry
.GetData()) {
118 info
.mMode
.Construct(request
->Data().lockMode());
119 info
.mName
.Construct(request
->Data().name());
120 info
.mClientId
.Construct(
121 static_cast<LockManagerParent
*>(request
->Manager())->mClientId
);
122 if (!snapshot
.mPending
.Value().AppendElement(info
, mozilla::fallible
)) {
123 return IPC_FAIL(this, "Out of memory");
127 for (const RefPtr
<LockRequestParent
>& request
: mManagedLocks
->mHeldLocks
) {
129 info
.mMode
.Construct(request
->Data().lockMode());
130 info
.mName
.Construct(request
->Data().name());
131 info
.mClientId
.Construct(
132 static_cast<LockManagerParent
*>(request
->Manager())->mClientId
);
133 if (!snapshot
.mHeld
.Value().AppendElement(info
, mozilla::fallible
)) {
134 return IPC_FAIL(this, "Out of memory");
141 already_AddRefed
<PLockRequestParent
> LockManagerParent::AllocPLockRequestParent(
142 const IPCLockRequest
& aRequest
) {
143 return MakeAndAddRef
<LockRequestParent
>(aRequest
);
146 IPCResult
LockManagerParent::RecvPLockRequestConstructor(
147 PLockRequestParent
* aActor
, const IPCLockRequest
& aRequest
) {
148 RefPtr
<LockRequestParent
> actor
= static_cast<LockRequestParent
*>(aActor
);
149 nsTArray
<RefPtr
<LockRequestParent
>>& queue
=
150 mManagedLocks
->mQueueMap
.LookupOrInsert(aRequest
.name());
151 if (aRequest
.steal()) {
152 mManagedLocks
->mHeldLocks
.RemoveElementsBy(
153 [&aRequest
](const RefPtr
<LockRequestParent
>& aHeld
) {
154 if (aHeld
->Data().name() == aRequest
.name()) {
155 Unused
<< NS_WARN_IF(
156 !PLockRequestParent::Send__delete__(aHeld
, true));
161 queue
.InsertElementAt(0, actor
);
162 } else if (aRequest
.ifAvailable() &&
163 (!queue
.IsEmpty() || !IsGrantableRequest(actor
->Data()))) {
164 Unused
<< NS_WARN_IF(!aActor
->SendResolve(aRequest
.lockMode(), false));
167 queue
.AppendElement(actor
);
169 ProcessRequestQueue(queue
);
173 } // namespace mozilla::dom::locks