tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LockManagerParent.cpp (5955B)


      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 "LockManagerParent.h"
      8 
      9 #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"
     17 
     18 namespace mozilla::dom::locks {
     19 
     20 static StaticAutoPtr<nsTHashMap<PrincipalHashKey, WeakPtr<ManagedLocks>>>
     21    sManagedLocksMap;
     22 
     23 using IPCResult = mozilla::ipc::IPCResult;
     24 
     25 LockManagerParent::LockManagerParent(NotNull<nsIPrincipal*> aPrincipal,
     26                                     const Maybe<nsID>& aClientId)
     27    : mPrincipal(aPrincipal) {
     28  if (aClientId.isSome()) {
     29    mClientId = NSID_TrimBracketsUTF16(aClientId.value());
     30  } else {
     31    mClientId = EmptyString();
     32  }
     33 
     34  if (!sManagedLocksMap) {
     35    sManagedLocksMap =
     36        new nsTHashMap<PrincipalHashKey, WeakPtr<ManagedLocks>>();
     37  } else {
     38    mManagedLocks = sManagedLocksMap->Get(aPrincipal);
     39  }
     40 
     41  if (!mManagedLocks) {
     42    mManagedLocks = new ManagedLocks();
     43    sManagedLocksMap->LookupOrInsert(aPrincipal, mManagedLocks);
     44  }
     45 }
     46 
     47 void LockManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
     48  if (!mManagedLocks) {
     49    return;
     50  }
     51 
     52  nsTArray<nsString> affectedResourceNames;
     53 
     54  mManagedLocks->mHeldLocks.RemoveElementsBy(
     55      [this, &affectedResourceNames](const RefPtr<LockRequestParent>& request) {
     56        bool equals = request->Manager() == this;
     57        if (equals) {
     58          affectedResourceNames.AppendElement(request->Data().name());
     59        }
     60        return equals;
     61      });
     62 
     63  for (auto& queue : mManagedLocks->mQueueMap) {
     64    queue.GetModifiableData()->RemoveElementsBy(
     65        [this, &name = queue.GetKey(),
     66         &affectedResourceNames](const RefPtr<LockRequestParent>& request) {
     67          bool equals = request->Manager() == this;
     68          if (equals) {
     69            affectedResourceNames.AppendElement(name);
     70          }
     71          return equals;
     72        });
     73  }
     74 
     75  for (const nsString& name : affectedResourceNames) {
     76    if (auto queue = mManagedLocks->mQueueMap.Lookup(name)) {
     77      ProcessRequestQueue(queue.Data());
     78    }
     79  }
     80 
     81  mManagedLocks = nullptr;
     82  // We just decreased the refcount and potentially deleted it, so check whether
     83  // the weak pointer still points to anything and remove the entry if not.
     84  if (!sManagedLocksMap->Get(mPrincipal)) {
     85    sManagedLocksMap->Remove(mPrincipal);
     86  }
     87 }
     88 
     89 void LockManagerParent::ProcessRequestQueue(
     90    nsTArray<RefPtr<LockRequestParent>>& aQueue) {
     91  while (aQueue.Length()) {
     92    RefPtr<LockRequestParent> first = aQueue[0];
     93    if (!IsGrantableRequest(first->Data())) {
     94      break;
     95    }
     96    aQueue.RemoveElementAt(0);
     97    mManagedLocks->mHeldLocks.AppendElement(first);
     98    (void)NS_WARN_IF(!first->SendResolve(first->Data().lockMode(), true));
     99  }
    100 }
    101 
    102 bool LockManagerParent::IsGrantableRequest(const IPCLockRequest& aRequest) {
    103  for (const auto& held : mManagedLocks->mHeldLocks) {
    104    if (held->Data().name() == aRequest.name()) {
    105      if (aRequest.lockMode() == LockMode::Exclusive) {
    106        return false;
    107      }
    108      MOZ_ASSERT(aRequest.lockMode() == LockMode::Shared);
    109      if (held->Data().lockMode() == LockMode::Exclusive) {
    110        return false;
    111      }
    112    }
    113  }
    114  return true;
    115 }
    116 
    117 IPCResult LockManagerParent::RecvQuery(QueryResolver&& aResolver) {
    118  LockManagerSnapshot snapshot;
    119  snapshot.mHeld.Construct();
    120  snapshot.mPending.Construct();
    121  for (const auto& queueMapEntry : mManagedLocks->mQueueMap) {
    122    for (const RefPtr<LockRequestParent>& request : queueMapEntry.GetData()) {
    123      LockInfo info;
    124      info.mMode.Construct(request->Data().lockMode());
    125      info.mName.Construct(request->Data().name());
    126      info.mClientId.Construct(
    127          static_cast<LockManagerParent*>(request->Manager())->mClientId);
    128      if (!snapshot.mPending.Value().AppendElement(info, mozilla::fallible)) {
    129        return IPC_FAIL(this, "Out of memory");
    130      };
    131    }
    132  }
    133  for (const RefPtr<LockRequestParent>& request : mManagedLocks->mHeldLocks) {
    134    LockInfo info;
    135    info.mMode.Construct(request->Data().lockMode());
    136    info.mName.Construct(request->Data().name());
    137    info.mClientId.Construct(
    138        static_cast<LockManagerParent*>(request->Manager())->mClientId);
    139    if (!snapshot.mHeld.Value().AppendElement(info, mozilla::fallible)) {
    140      return IPC_FAIL(this, "Out of memory");
    141    };
    142  }
    143  aResolver(snapshot);
    144  return IPC_OK();
    145 };
    146 
    147 already_AddRefed<PLockRequestParent> LockManagerParent::AllocPLockRequestParent(
    148    const IPCLockRequest& aRequest) {
    149  return MakeAndAddRef<LockRequestParent>(aRequest);
    150 }
    151 
    152 IPCResult LockManagerParent::RecvPLockRequestConstructor(
    153    PLockRequestParent* aActor, const IPCLockRequest& aRequest) {
    154  RefPtr<LockRequestParent> actor = static_cast<LockRequestParent*>(aActor);
    155  nsTArray<RefPtr<LockRequestParent>>& queue =
    156      mManagedLocks->mQueueMap.LookupOrInsert(aRequest.name());
    157  if (aRequest.steal()) {
    158    mManagedLocks->mHeldLocks.RemoveElementsBy(
    159        [&aRequest](const RefPtr<LockRequestParent>& aHeld) {
    160          if (aHeld->Data().name() == aRequest.name()) {
    161            (void)NS_WARN_IF(!PLockRequestParent::Send__delete__(aHeld, true));
    162            return true;
    163          }
    164          return false;
    165        });
    166    queue.InsertElementAt(0, actor);
    167  } else if (aRequest.ifAvailable() &&
    168             (!queue.IsEmpty() || !IsGrantableRequest(actor->Data()))) {
    169    (void)NS_WARN_IF(!aActor->SendResolve(aRequest.lockMode(), false));
    170    return IPC_OK();
    171  } else {
    172    queue.AppendElement(actor);
    173  }
    174  ProcessRequestQueue(queue);
    175  return IPC_OK();
    176 }
    177 
    178 }  // namespace mozilla::dom::locks