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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/* This source code was derived from Chromium code, and as such is also subject
* to the [Chromium license](ipc/chromium/src/LICENSE). */
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "SharedMemoryPlatform.h"
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/Atomics.h"
#include "nsDebug.h"
#include "nsIMemoryReporter.h"
namespace mozilla::ipc::shared_memory {
// Implementation of the shared memory logger in SharedMemoryPlatform.h.
LazyLogModule gSharedMemoryLog{"SharedMemory"};
class AllocationReporter final : public nsIMemoryReporter {
~AllocationReporter() = default;
public:
static Atomic<uint64_t> allocated;
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
bool aAnonymize) override {
MOZ_COLLECT_REPORT(
"shmem-allocated", KIND_OTHER, UNITS_BYTES, allocated,
"Memory shared with other processes that is accessible (but not "
"necessarily mapped).");
return NS_OK;
}
};
Atomic<uint64_t> AllocationReporter::allocated;
NS_IMPL_ISUPPORTS(AllocationReporter, nsIMemoryReporter)
static void RegisterAllocationMemoryReporter() {
static Atomic<bool> registered;
if (registered.compareExchange(false, true)) {
RegisterStrongMemoryReporter(new AllocationReporter());
}
}
HandleBase::HandleBase() = default;
HandleBase::~HandleBase() {
if (mSize > 0) {
MOZ_ASSERT(AllocationReporter::allocated >= mSize,
"Can't destroy more than allocated");
SetSize(0);
}
mHandle = nullptr;
}
HandleBase& HandleBase::operator=(HandleBase&& aOther) {
mHandle = std::move(aOther.mHandle);
SetSize(std::exchange(aOther.mSize, 0));
return *this;
}
HandleBase HandleBase::Clone() const {
HandleBase hb;
hb.mHandle = Platform::CloneHandle(mHandle);
if (hb.mHandle) {
// TODO more intelligently handle clones to not count as additional
// allocations?
hb.SetSize(mSize);
}
return hb;
}
void HandleBase::ToMessageWriter(IPC::MessageWriter* aWriter) && {
WriteParam(aWriter, std::move(mHandle));
WriteParam(aWriter, mSize);
SetSize(0);
}
bool HandleBase::FromMessageReader(IPC::MessageReader* aReader) {
mozilla::ipc::shared_memory::PlatformHandle handle;
if (!ReadParam(aReader, &handle)) {
aReader->FatalError("Failed to read shared memory PlatformHandle");
return false;
}
if (handle && !Platform::IsSafeToMap(handle)) {
aReader->FatalError("Shared memory PlatformHandle is not safe to map");
return false;
}
uint64_t size = 0;
if (!ReadParam(aReader, &size)) {
aReader->FatalError("Failed to read shared memory handle size");
return false;
}
if (handle && !size) {
aReader->FatalError(
"Unexpected PlatformHandle for zero-sized shared memory handle");
return false;
}
mHandle = std::move(handle);
SetSize(size);
return true;
}
void HandleBase::SetSize(uint64_t aSize) {
RegisterAllocationMemoryReporter();
mozilla::ipc::shared_memory::AllocationReporter::allocated -= mSize;
mSize = aSize;
mozilla::ipc::shared_memory::AllocationReporter::allocated += mSize;
}
MutableMapping MutableHandle::Map(void* aFixedAddress) const {
return MutableMapping(*this, aFixedAddress);
}
MutableMapping MutableHandle::MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress) const {
return MutableMapping(*this, aOffset, aSize, aFixedAddress);
}
MutableMappingWithHandle MutableHandle::MapWithHandle(void* aFixedAddress) && {
return MutableMappingWithHandle(std::move(*this), aFixedAddress);
}
ReadOnlyHandle MutableHandle::ToReadOnly() && {
return std::move(*this).ConvertTo<Type::ReadOnly>();
}
const ReadOnlyHandle& MutableHandle::AsReadOnly() const {
static_assert(sizeof(ReadOnlyHandle) == sizeof(MutableHandle));
return reinterpret_cast<const ReadOnlyHandle&>(*this);
}
ReadOnlyMapping ReadOnlyHandle::Map(void* aFixedAddress) const {
return ReadOnlyMapping(*this, aFixedAddress);
}
ReadOnlyMapping ReadOnlyHandle::MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress) const {
return ReadOnlyMapping(*this, aOffset, aSize, aFixedAddress);
}
ReadOnlyMappingWithHandle ReadOnlyHandle::MapWithHandle(
void* aFixedAddress) && {
return ReadOnlyMappingWithHandle(std::move(*this), aFixedAddress);
}
FreezableHandle::~Handle() {
NS_WARNING_ASSERTION(!IsValid(), "freezable shared memory was never frozen");
}
MutableHandle FreezableHandle::WontFreeze() && {
return std::move(*this).ConvertTo<Type::Mutable>();
}
ReadOnlyHandle FreezableHandle::Freeze() && {
DebugOnly<const uint64_t> previous_size = Size();
if (Platform::Freeze(*this)) {
MOZ_ASSERT(Size() == previous_size);
return std::move(*this).ConvertTo<Type::ReadOnly>();
}
return nullptr;
}
FreezableMapping FreezableHandle::Map(void* aFixedAddress) && {
return FreezableMapping(std::move(*this), aFixedAddress);
}
FreezableMapping FreezableHandle::MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress) && {
return FreezableMapping(std::move(*this), aOffset, aSize, aFixedAddress);
}
MutableHandle Create(uint64_t aSize) {
MutableHandle h;
const auto success = Platform::Create(h, aSize);
MOZ_ASSERT(success == h.IsValid());
if (success) {
MOZ_ASSERT(aSize == h.Size());
}
return h;
}
FreezableHandle CreateFreezable(uint64_t aSize) {
FreezableHandle h;
const auto success = Platform::CreateFreezable(h, aSize);
MOZ_ASSERT(success == h.IsValid());
if (success) {
MOZ_ASSERT(aSize == h.Size());
}
return h;
}
} // namespace mozilla::ipc::shared_memory
namespace IPC {
void ParamTraits<mozilla::ipc::shared_memory::MutableHandle>::Write(
MessageWriter* aWriter,
mozilla::ipc::shared_memory::MutableHandle&& aParam) {
std::move(aParam).ToMessageWriter(aWriter);
}
bool ParamTraits<mozilla::ipc::shared_memory::MutableHandle>::Read(
MessageReader* aReader,
mozilla::ipc::shared_memory::MutableHandle* aResult) {
return aResult->FromMessageReader(aReader);
}
void ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>::Write(
MessageWriter* aWriter,
mozilla::ipc::shared_memory::ReadOnlyHandle&& aParam) {
std::move(aParam).ToMessageWriter(aWriter);
}
bool ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>::Read(
MessageReader* aReader,
mozilla::ipc::shared_memory::ReadOnlyHandle* aResult) {
return aResult->FromMessageReader(aReader);
}
} // namespace IPC
|