tor-browser

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

SharedMemoryCursor.cpp (3517B)


      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 "mozilla/MathAlgorithms.h"
      8 #include "nsDebug.h"
      9 #include "SharedMemoryCursor.h"
     10 
     11 namespace mozilla::ipc::shared_memory {
     12 
     13 bool Cursor::Read(void* aBuffer, size_t aCount) {
     14  return Consume(aBuffer, aCount, /* aWriteToShmem */ false);
     15 }
     16 
     17 bool Cursor::Write(const void* aBuffer, size_t aCount) {
     18  return Consume(const_cast<void*>(aBuffer), aCount, /* aWriteToShmem */ true);
     19 }
     20 
     21 void Cursor::Seek(uint64_t aOffset) {
     22  MOZ_ASSERT(aOffset <= Size());
     23 
     24  // Update our offset, and invalidate `mMapping` if our current chunk changed.
     25  uint64_t oldChunkStart = ChunkStart();
     26  mOffset = aOffset;
     27  if (mMapping && oldChunkStart != ChunkStart()) {
     28    mMapping = nullptr;
     29  }
     30 }
     31 
     32 MutableHandle Cursor::TakeHandle() {
     33  mMapping = nullptr;
     34  return std::move(mHandle);
     35 }
     36 
     37 void Cursor::SetChunkSize(size_t aChunkSize) {
     38  MOZ_ASSERT(IsPowerOfTwo(aChunkSize),
     39             "Cannot specify non power-of-two maximum chunk size");
     40  MOZ_ASSERT(aChunkSize >= SystemAllocationGranularity(),
     41             "Cannot specify a chunk size which is smaller than the system "
     42             "allocation granularity");
     43  mChunkSize = aChunkSize;
     44  mMapping = nullptr;  // Invalidate any existing mappings.
     45 }
     46 
     47 bool Cursor::Consume(void* aBuffer, size_t aCount, bool aWriteToShmem) {
     48  if (aCount > Remaining()) {
     49    NS_WARNING("count too large");
     50    return false;
     51  }
     52 
     53  size_t consumed = 0;
     54  while (consumed < aCount) {
     55    // Ensure we have a valid mapping each trip through the loop. This will
     56    // automatically back off on chunk size to avoid mapping failure.
     57    if (!EnsureMapping()) {
     58      return false;
     59    }
     60 
     61    // Determine how many of the requested bytes are available in mMapping, and
     62    // perform the operation on them.
     63    size_t mappingOffset = ChunkOffset();
     64    size_t mappingRemaining = mMapping.Size() - mappingOffset;
     65    size_t toCopy = std::min<size_t>(mappingRemaining, aCount - consumed);
     66 
     67    void* shmemPtr = mMapping.DataAs<char>() + mappingOffset;
     68    void* bufferPtr = static_cast<char*>(aBuffer) + consumed;
     69    if (aWriteToShmem) {
     70      memcpy(shmemPtr, bufferPtr, toCopy);
     71    } else {
     72      memcpy(bufferPtr, shmemPtr, toCopy);
     73    }
     74 
     75    // Seek and advance offsets. This will invalidate our mapping if it no
     76    // longer applies to the current chunk.
     77    Seek(mOffset + toCopy);
     78    consumed += toCopy;
     79  }
     80  return true;
     81 }
     82 
     83 bool Cursor::EnsureMapping() {
     84  MOZ_ASSERT(mHandle.IsValid());
     85 
     86  while (!mMapping) {
     87    // Attempt to map at the current chunk size.
     88    uint64_t chunkStart = ChunkStart();
     89    size_t chunkSize = std::min<uint64_t>(ChunkSize(), Size() - chunkStart);
     90    mMapping = mHandle.MapSubregion(chunkStart, chunkSize);
     91    if (MOZ_UNLIKELY(!mMapping)) {
     92      // If we failed to map a single allocation granularity, we can't go
     93      // smaller, so give up.
     94      if (chunkSize <= SystemAllocationGranularity()) {
     95        NS_WARNING(
     96            "Failed to map the smallest allocation granularity of shared "
     97            "memory region!");
     98        return false;
     99      }
    100      // Try to allocate a smaller chunk next time.
    101      mChunkSize = RoundUpPow2(chunkSize) >> 1;
    102    }
    103  }
    104  return true;
    105 }
    106 
    107 }  // namespace mozilla::ipc::shared_memory