tor-browser

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

ProfileBufferChunkManager.h (5284B)


      1 /* -*- Mode: C++; tab-width: 2; 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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef ProfileBufferChunkManager_h
      8 #define ProfileBufferChunkManager_h
      9 
     10 #include "mozilla/ProfileBufferChunk.h"
     11 #include "mozilla/ScopeExit.h"
     12 
     13 #include <functional>
     14 
     15 namespace mozilla {
     16 
     17 // Manages the ProfileBufferChunks for this process.
     18 // The main user of this class is the buffer that needs chunks to store its
     19 // data.
     20 // The main ProfileBufferChunks responsibilities are:
     21 // - It can create new chunks, they are called "unreleased".
     22 // - Later these chunks are returned here, and become "released".
     23 // - The manager is free to destroy or recycle the oldest released chunks
     24 //   (usually to reclaim memory), and will inform the user through a provided
     25 //   callback.
     26 // - The user may access still-alive released chunks.
     27 class ProfileBufferChunkManager {
     28 public:
     29  virtual ~ProfileBufferChunkManager()
     30 #ifdef DEBUG
     31  {
     32    MOZ_ASSERT(!mUser, "Still registered when being destroyed");
     33  }
     34 #else
     35      = default;
     36 #endif
     37 
     38  // Expected maximum size needed to store one stack sample.
     39  // Most ChunkManager sub-classes will require chunk sizes, this can serve as
     40  // a minimum recommendation to hold most backtraces.
     41  constexpr static ProfileBufferChunk::Length scExpectedMaximumStackSize =
     42      128 * 1024;
     43 
     44  // Estimated maximum buffer size.
     45  [[nodiscard]] virtual size_t MaxTotalSize() const = 0;
     46 
     47  // Create or recycle a chunk right now. May return null in case of allocation
     48  // failure.
     49  // Note that the chunk-destroyed callback may be invoked during this call;
     50  // user should be careful with reentrancy issues.
     51  [[nodiscard]] virtual UniquePtr<ProfileBufferChunk> GetChunk() = 0;
     52 
     53  // `aChunkReceiver` may be called with a new or recycled chunk, or nullptr.
     54  // (See `FulfillChunkRequests()` regarding when the callback may happen.)
     55  virtual void RequestChunk(
     56      std::function<void(UniquePtr<ProfileBufferChunk>)>&& aChunkReceiver) = 0;
     57 
     58  // This method may be invoked at any time on any thread (and not necessarily
     59  // by the main user of this class), to do the work necessary to respond to a
     60  // previous `RequestChunk()`.
     61  // It is optional: If it is never called, or called too late, the user is
     62  // responsible for directly calling `GetChunk()` when a chunk is really
     63  // needed (or it should at least fail gracefully).
     64  // The idea is to fulfill chunk request on a separate thread, and most
     65  // importantly outside of profiler calls, to avoid doing expensive memory
     66  // allocations during these calls.
     67  virtual void FulfillChunkRequests() = 0;
     68 
     69  // One chunk is released by the user, the ProfileBufferChunkManager should
     70  // keep it as long as possible (depending on local or global memory/time
     71  // limits). Note that the chunk-destroyed callback may be invoked during this
     72  // call; user should be careful with reentrancy issues.
     73  virtual void ReleaseChunk(UniquePtr<ProfileBufferChunk> aChunk) = 0;
     74 
     75  // `aChunkDestroyedCallback` will be called whenever the contents of a
     76  // previously-released chunk is about to be destroyed or recycled.
     77  // Note that it may be called during other functions above, or at other times
     78  // from the same or other threads; user should be careful with reentrancy
     79  // issues.
     80  virtual void SetChunkDestroyedCallback(
     81      std::function<void(const ProfileBufferChunk&)>&&
     82          aChunkDestroyedCallback) = 0;
     83 
     84  // Give away all released chunks that have not yet been destroyed.
     85  [[nodiscard]] virtual UniquePtr<ProfileBufferChunk>
     86  GetExtantReleasedChunks() = 0;
     87 
     88  // Let a callback see all released chunks that have not yet been destroyed, if
     89  // any. Return whatever the callback returns.
     90  template <typename Callback>
     91  [[nodiscard]] auto PeekExtantReleasedChunks(Callback&& aCallback) {
     92    const ProfileBufferChunk* chunks = PeekExtantReleasedChunksAndLock();
     93    auto unlock =
     94        MakeScopeExit([&]() { UnlockAfterPeekExtantReleasedChunks(); });
     95    return std::forward<Callback>(aCallback)(chunks);
     96  }
     97 
     98  // Chunks that were still unreleased will never be released.
     99  virtual void ForgetUnreleasedChunks() = 0;
    100 
    101  [[nodiscard]] virtual size_t SizeOfExcludingThis(
    102      MallocSizeOf aMallocSizeOf) const = 0;
    103  [[nodiscard]] virtual size_t SizeOfIncludingThis(
    104      MallocSizeOf aMallocSizeOf) const = 0;
    105 
    106 protected:
    107  // Derived classes to implement `PeekExtantReleasedChunks` through these:
    108  virtual const ProfileBufferChunk* PeekExtantReleasedChunksAndLock() = 0;
    109  virtual void UnlockAfterPeekExtantReleasedChunks() = 0;
    110 
    111 #ifdef DEBUG
    112 public:
    113  // DEBUG checks ensuring that this manager and its users avoid UAFs.
    114  // Derived classes should assert that mUser is not null in their functions.
    115 
    116  void RegisteredWith(const void* aUser) {
    117    MOZ_ASSERT(!mUser);
    118    MOZ_ASSERT(aUser);
    119    mUser = aUser;
    120  }
    121 
    122  void DeregisteredFrom(const void* aUser) {
    123    MOZ_ASSERT(mUser == aUser);
    124    mUser = nullptr;
    125  }
    126 
    127 protected:
    128  const void* mUser = nullptr;
    129 #endif  // DEBUG
    130 };
    131 
    132 }  // namespace mozilla
    133 
    134 #endif  // ProfileBufferChunkManager_h