tor-browser

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

DirectoryLockImpl.h (8350B)


      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 #ifndef DOM_QUOTA_DIRECTORYLOCKIMPL_H_
      8 #define DOM_QUOTA_DIRECTORYLOCKIMPL_H_
      9 
     10 #include <cstdint>
     11 #include <functional>
     12 
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/Attributes.h"
     15 #include "mozilla/EnumSet.h"
     16 #include "mozilla/MozPromise.h"
     17 #include "mozilla/NotNull.h"
     18 #include "mozilla/RefPtr.h"
     19 #include "mozilla/dom/FlippedOnce.h"
     20 #include "mozilla/dom/Nullable.h"
     21 #include "mozilla/dom/quota/Client.h"
     22 #include "mozilla/dom/quota/ClientStorageScope.h"
     23 #include "mozilla/dom/quota/CommonMetadata.h"
     24 #include "mozilla/dom/quota/DirectoryLockCategory.h"
     25 #include "mozilla/dom/quota/ForwardDecls.h"
     26 #include "mozilla/dom/quota/OriginScope.h"
     27 #include "mozilla/dom/quota/PersistenceScope.h"
     28 #include "mozilla/dom/quota/PersistenceType.h"
     29 #include "nsCOMPtr.h"
     30 #include "nsISupportsImpl.h"
     31 #include "nsTArray.h"
     32 
     33 class nsITimer;
     34 
     35 namespace mozilla::dom::quota {
     36 
     37 class ClientDirectoryLockHandle;
     38 struct OriginMetadata;
     39 class QuotaManager;
     40 
     41 enum class ShouldUpdateLockIdTableFlag { No, Yes };
     42 
     43 // XXX Rename to DirectoryLockBase.
     44 class DirectoryLockImpl {
     45 public:
     46  class PrepareInfo;
     47 
     48 private:
     49  friend class ClientDirectoryLock;
     50  friend class ClientDirectoryLockHandle;
     51  friend class OriginDirectoryLock;
     52  friend class QuotaManager;
     53  friend class UniversalDirectoryLock;
     54 
     55  const NotNull<RefPtr<QuotaManager>> mQuotaManager;
     56 
     57  const PersistenceScope mPersistenceScope;
     58  const OriginScope mOriginScope;
     59  const ClientStorageScope mClientStorageScope;
     60 
     61  MozPromiseHolder<BoolPromise> mAcquirePromiseHolder;
     62  nsCOMPtr<nsITimer> mAcquireTimer;
     63 
     64  nsTArray<NotNull<DirectoryLockImpl*>> mBlocking;
     65  nsTArray<NotNull<DirectoryLockImpl*>> mBlockedOn;
     66 
     67  std::function<void()> mInvalidateCallback;
     68 
     69  const int64_t mId;
     70 
     71  const bool mExclusive;
     72 
     73  // Internal quota manager operations use this flag to prevent directory lock
     74  // registraction/unregistration from updating origin access time, etc.
     75  const bool mInternal;
     76 
     77  const bool mShouldUpdateLockIdTable;
     78 
     79  const DirectoryLockCategory mCategory;
     80 
     81  bool mRegistered;
     82  FlippedOnce<true> mPending;
     83  FlippedOnce<false> mAcquired;
     84  FlippedOnce<false> mInvalidated;
     85  FlippedOnce<false> mDropped;
     86 
     87 public:
     88  DirectoryLockImpl(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
     89                    const PersistenceScope& aPersistenceScope,
     90                    const OriginScope& aOriginScope,
     91                    const ClientStorageScope& aClientStorageScope,
     92                    bool aExclusive, bool aInternal,
     93                    ShouldUpdateLockIdTableFlag aShouldUpdateLockIdTableFlag,
     94                    DirectoryLockCategory aCategory);
     95 
     96  NS_INLINE_DECL_REFCOUNTING(DirectoryLockImpl)
     97 
     98  QuotaManager& MutableManagerRef() const { return *mQuotaManager; }
     99 
    100  int64_t Id() const { return mId; }
    101 
    102  const PersistenceScope& PersistenceScopeRef() const {
    103    return mPersistenceScope;
    104  }
    105 
    106  const OriginScope& GetOriginScope() const { return mOriginScope; }
    107 
    108  const ClientStorageScope& ClientStorageScopeRef() const {
    109    return mClientStorageScope;
    110  }
    111 
    112  DirectoryLockCategory Category() const { return mCategory; }
    113 
    114  bool Acquired() const { return mAcquired; }
    115 
    116  bool MustWait() const;
    117 
    118  nsTArray<RefPtr<DirectoryLockImpl>> LocksMustWaitFor() const;
    119 
    120  bool Invalidated() const { return mInvalidated; }
    121 
    122  bool Dropped() const { return mDropped; }
    123 
    124  PrepareInfo Prepare() const;
    125 
    126  RefPtr<BoolPromise> Acquire();
    127 
    128  RefPtr<BoolPromise> Acquire(PrepareInfo&& aPrepareInfo);
    129 
    130  void AcquireImmediately();
    131 
    132  void AssertIsAcquiredExclusively()
    133 #ifdef DEBUG
    134      ;
    135 #else
    136  {
    137  }
    138 #endif
    139 
    140  RefPtr<BoolPromise> Drop();
    141 
    142  void OnInvalidate(std::function<void()>&& aCallback);
    143 
    144  void Log() const;
    145 
    146 private:
    147  virtual ~DirectoryLockImpl();
    148 
    149  void AssertIsOnOwningThread() const
    150 #ifdef DEBUG
    151      ;
    152 #else
    153  {
    154  }
    155 #endif
    156 
    157  PersistenceType GetPersistenceType() const {
    158    MOZ_DIAGNOSTIC_ASSERT(mPersistenceScope.IsValue());
    159 
    160    return mPersistenceScope.GetValue();
    161  }
    162 
    163  quota::OriginMetadata OriginMetadata() const {
    164    MOZ_DIAGNOSTIC_ASSERT(mOriginScope.IsOrigin());
    165 
    166    return quota::OriginMetadata{mOriginScope.GetPrincipalMetadata(),
    167                                 GetPersistenceType()};
    168  }
    169 
    170  const nsACString& Origin() const {
    171    MOZ_DIAGNOSTIC_ASSERT(mOriginScope.IsOrigin());
    172    MOZ_DIAGNOSTIC_ASSERT(!mOriginScope.GetOrigin().IsEmpty());
    173 
    174    return mOriginScope.GetOrigin();
    175  }
    176 
    177  Client::Type ClientType() const {
    178    MOZ_DIAGNOSTIC_ASSERT(mClientStorageScope.IsClient());
    179    MOZ_DIAGNOSTIC_ASSERT(mClientStorageScope.GetClientType() <
    180                          Client::TypeMax());
    181 
    182    return mClientStorageScope.GetClientType();
    183  }
    184 
    185  bool IsInternal() const { return mInternal; }
    186 
    187  void SetRegistered(bool aRegistered) { mRegistered = aRegistered; }
    188 
    189  bool IsPending() const { return mPending; }
    190 
    191  // Ideally, we would have just one table (instead of these two:
    192  // QuotaManager::mDirectoryLocks and QuotaManager::mDirectoryLockIdTable) for
    193  // all registered locks. However, some directory locks need to be accessed off
    194  // the PBackground thread, so the access must be protected by the quota mutex.
    195  // The problem is that directory locks for eviction must be currently created
    196  // while the mutex lock is already acquired. So we decided to have two tables
    197  // for now and to not register directory locks for eviction in
    198  // QuotaManager::mDirectoryLockIdTable. This can be improved in future after
    199  // some refactoring of the mutex locking.
    200  bool ShouldUpdateLockIdTable() const { return mShouldUpdateLockIdTable; }
    201 
    202  bool Overlaps(const DirectoryLockImpl& aLock) const;
    203 
    204  // Test whether this DirectoryLock needs to wait for the given lock.
    205  bool MustWaitFor(const DirectoryLockImpl& aLock) const;
    206 
    207  void AddBlockingLock(DirectoryLockImpl& aLock) {
    208    AssertIsOnOwningThread();
    209 
    210    mBlocking.AppendElement(WrapNotNull(&aLock));
    211  }
    212 
    213  const nsTArray<NotNull<DirectoryLockImpl*>>& GetBlockedOnLocks() {
    214    return mBlockedOn;
    215  }
    216 
    217  void AddBlockedOnLock(DirectoryLockImpl& aLock) {
    218    AssertIsOnOwningThread();
    219 
    220    mBlockedOn.AppendElement(WrapNotNull(&aLock));
    221  }
    222 
    223  void MaybeUnblock(DirectoryLockImpl& aLock) {
    224    AssertIsOnOwningThread();
    225 
    226    mBlockedOn.RemoveElement(&aLock);
    227    if (mBlockedOn.IsEmpty()) {
    228      NotifyOpenListener();
    229    }
    230  }
    231 
    232  void NotifyOpenListener();
    233 
    234  template <typename T>
    235  nsTArray<T> LocksMustWaitForInternal() const;
    236 
    237  void AcquireInternal(PrepareInfo&& aPrepareInfo);
    238 
    239  void Invalidate();
    240 
    241  void Unregister();
    242 };
    243 
    244 class MOZ_RAII DirectoryLockImpl::PrepareInfo {
    245  friend class DirectoryLockImpl;
    246 
    247  nsTArray<NotNull<DirectoryLockImpl*>> mBlockedOn;
    248 
    249 public:
    250  // Disable copy constructor and assignment operator
    251  PrepareInfo(const PrepareInfo&) = delete;
    252  PrepareInfo& operator=(const PrepareInfo&) = delete;
    253 
    254  // Move constructor and move assignment operator
    255  PrepareInfo(PrepareInfo&&) noexcept = default;
    256  PrepareInfo& operator=(PrepareInfo&&) noexcept = default;
    257 
    258  const nsTArray<NotNull<DirectoryLockImpl*>>& BlockedOnRef() const {
    259    return mBlockedOn;
    260  }
    261 
    262  /**
    263   * Returns true if this directory lock would be blocked by any other lock
    264   * whose category is included in the given set.
    265   *
    266   * Used to detect whether an initialization operation should still run, even
    267   * if the cached state indicates it has already been performed, because an
    268   * in-progress or pending uninitialization operation will eventually
    269   * invalidate that state.
    270   */
    271  bool IsBlockedBy(const EnumSet<DirectoryLockCategory>& aCategories) const {
    272    return std::any_of(mBlockedOn.cbegin(), mBlockedOn.cend(),
    273                       [&aCategories](const auto& lock) {
    274                         return aCategories.contains(lock->Category());
    275                       });
    276  }
    277 
    278 private:
    279  explicit PrepareInfo(const DirectoryLockImpl& aDirectoryLock)
    280      : mBlockedOn(
    281            aDirectoryLock
    282                .LocksMustWaitForInternal<NotNull<DirectoryLockImpl*>>()) {}
    283 };
    284 
    285 }  // namespace mozilla::dom::quota
    286 
    287 #endif  // DOM_QUOTA_DIRECTORYLOCKIMPL_H_