DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (3cc34f31408f)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozalloc_VolatileBuffer_h
#define mozalloc_VolatileBuffer_h

#include "mozilla/mozalloc.h"
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/RefCounted.h"

/* VolatileBuffer
 *
 * This class represents a piece of memory that can potentially be reclaimed
 * by the OS when not in use. As long as there are one or more
 * VolatileBufferPtrs holding on to a VolatileBuffer, the memory will remain
 * available. However, when there are no VolatileBufferPtrs holding a
 * VolatileBuffer, the OS can purge the pages if it wants to. The OS can make
 * better decisions about what pages to purge than we can.
 *
 * VolatileBuffers may not always be volatile - if the allocation is too small,
 * or if the OS doesn't support the feature, or if the OS doesn't want to,
 * the buffer will be allocated on heap.
 *
 * VolatileBuffer allocations are fallible. They are intended for uses where
 * one may allocate large buffers for caching data. Init() must be called
 * exactly once.
 *
 * After getting a reference to VolatileBuffer using VolatileBufferPtr,
 * WasPurged() can be used to check if the OS purged any pages in the buffer.
 * The OS cannot purge a buffer immediately after a VolatileBuffer is
 * initialized. At least one VolatileBufferPtr must be created before the
 * buffer can be purged, so the first use of VolatileBufferPtr does not need
 * to check WasPurged().
 *
 * When a buffer is purged, some or all of the buffer is zeroed out. This
 * API cannot tell which parts of the buffer were lost.
 *
 * VolatileBuffer and VolatileBufferPtr are threadsafe.
 */

namespace mozilla {

class VolatileBuffer {
  friend class VolatileBufferPtr_base;

 public:
  MOZ_DECLARE_REFCOUNTED_TYPENAME(VolatileBuffer)
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VolatileBuffer)

  VolatileBuffer();

  /* aAlignment must be a multiple of the pointer size */
  bool Init(size_t aSize, size_t aAlignment = sizeof(void*));

  size_t HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
  size_t NonHeapSizeOfExcludingThis() const;
  bool OnHeap() const;

 protected:
  bool Lock(void** aBuf);
  void Unlock();

 private:
  ~VolatileBuffer();

  /**
   * Protects mLockCount, mFirstLock, and changes to the volatility of our
   * buffer.  Other member variables are read-only except in Init() and the
   * destructor.
   */
  Mutex mMutex;

  void* mBuf;
  size_t mSize;
  int mLockCount;
#if defined(ANDROID)
  int mFd;
#elif defined(XP_DARWIN)
  bool mHeap;
#elif defined(XP_WIN)
  bool mHeap;
  bool mFirstLock;
#endif
};

class VolatileBufferPtr_base {
 public:
  explicit VolatileBufferPtr_base(VolatileBuffer* vbuf)
      : mVBuf(vbuf), mMapping(nullptr), mPurged(false) {
    Lock();
  }

  ~VolatileBufferPtr_base() { Unlock(); }

  bool WasBufferPurged() const { return mPurged; }

 protected:
  RefPtr<VolatileBuffer> mVBuf;
  void* mMapping;

  void Set(VolatileBuffer* vbuf) {
    Unlock();
    mVBuf = vbuf;
    Lock();
  }

 private:
  bool mPurged;

  void Lock() {
    if (mVBuf) {
      mPurged = !mVBuf->Lock(&mMapping);
    } else {
      mMapping = nullptr;
      mPurged = false;
    }
  }

  void Unlock() {
    if (mVBuf) {
      mVBuf->Unlock();
    }
  }
};

template <class T>
class VolatileBufferPtr : public VolatileBufferPtr_base {
 public:
  explicit VolatileBufferPtr(VolatileBuffer* vbuf)
      : VolatileBufferPtr_base(vbuf) {}
  VolatileBufferPtr() : VolatileBufferPtr_base(nullptr) {}

  VolatileBufferPtr(VolatileBufferPtr&& aOther)
      : VolatileBufferPtr_base(aOther.mVBuf) {
    aOther.Set(nullptr);
  }

  operator T*() const { return (T*)mMapping; }

  VolatileBufferPtr& operator=(VolatileBuffer* aVBuf) {
    Set(aVBuf);
    return *this;
  }

  VolatileBufferPtr& operator=(VolatileBufferPtr&& aOther) {
    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
    Set(aOther.mVBuf);
    aOther.Set(nullptr);
    return *this;
  }

 private:
  VolatileBufferPtr(VolatileBufferPtr const& vbufptr) = delete;
};

}  // namespace mozilla

#endif /* mozalloc_VolatileBuffer_h */