diff options
Diffstat (limited to 'ipc/glue/BigBuffer.h')
-rw-r--r-- | ipc/glue/BigBuffer.h | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/ipc/glue/BigBuffer.h b/ipc/glue/BigBuffer.h new file mode 100644 index 0000000000..7136b6c03c --- /dev/null +++ b/ipc/glue/BigBuffer.h @@ -0,0 +1,131 @@ +/* -*- 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/. */ + +#ifndef mozilla_ipc_BigBuffer_h +#define mozilla_ipc_BigBuffer_h + +#include <stdlib.h> +#include <inttypes.h> +#include "mozilla/Span.h" +#include "mozilla/Variant.h" +#include "mozilla/ipc/SharedMemory.h" + +namespace mozilla::ipc { + +class BigBuffer { + public: + static constexpr size_t kShmemThreshold = 64 * 1024; + + static BigBuffer TryAlloc(const size_t aSize) { + auto ret = BigBuffer{}; + auto data = TryAllocBuffer(aSize); + if (data) { + ret.mSize = aSize; + ret.mData = std::move(data.ref()); + } + return ret; + } + + // Return a new BigBuffer which wraps no data. + BigBuffer() : mSize(0), mData(NoData()) {} + + BigBuffer(const BigBuffer&) = delete; + BigBuffer& operator=(const BigBuffer&) = delete; + + BigBuffer(BigBuffer&& aOther) noexcept + : mSize(std::exchange(aOther.mSize, 0)), + mData(std::exchange(aOther.mData, NoData())) {} + + BigBuffer& operator=(BigBuffer&& aOther) noexcept { + mSize = std::exchange(aOther.mSize, 0); + mData = std::exchange(aOther.mData, NoData()); + return *this; + } + + // Create a new BigBuffer with the given size. + // The buffer will be created uninitialized and must be fully initialized + // before sending over IPC to avoid leaking uninitialized memory to another + // process. + explicit BigBuffer(size_t aSize) : mSize(aSize), mData(AllocBuffer(aSize)) {} + + // Create a new BigBuffer containing the data from the provided byte slice. + explicit BigBuffer(Span<const uint8_t> aData) : BigBuffer(aData.Length()) { + memcpy(Data(), aData.Elements(), aData.Length()); + } + + // Marker to indicate that a particular constructor of BigBuffer adopts + // ownership of the provided data. + struct Adopt {}; + + // Create a new BigBuffer from an existing shared memory region, taking + // ownership of that shared memory region. The shared memory region must be + // non-null, mapped, and large enough to fit aSize bytes. + BigBuffer(Adopt, SharedMemory* aSharedMemory, size_t aSize); + + // Create a new BigBuffer from an existing memory buffer, taking ownership of + // that memory region. The region will be freed using `free()` when it is no + // longer needed. + BigBuffer(Adopt, uint8_t* aData, size_t aSize); + + ~BigBuffer() = default; + + // Returns a pointer to the data stored by this BigBuffer, regardless of + // backing storage type. + uint8_t* Data(); + const uint8_t* Data() const; + + // Returns the size of the data stored by this BigBuffer, regardless of + // backing storage type. + size_t Size() const { return mSize; } + + // Get a view of the BigBuffer's data as a span. + Span<uint8_t> AsSpan() { return Span{Data(), Size()}; } + Span<const uint8_t> AsSpan() const { return Span{Data(), Size()}; } + + // If the BigBuffer is backed by shared memory, returns a pointer to the + // backing SharedMemory region. + SharedMemory* GetSharedMemory() const { + return mData.is<1>() ? mData.as<1>().get() : nullptr; + } + + private: + friend struct IPC::ParamTraits<mozilla::ipc::BigBuffer>; + + using Storage = Variant<UniqueFreePtr<uint8_t[]>, RefPtr<SharedMemory>>; + + // Empty storage which holds no data. + static Storage NoData() { return AsVariant(UniqueFreePtr<uint8_t[]>{}); } + + // Fallibly allocate a new storage of the given size. + static Maybe<Storage> TryAllocBuffer(size_t aSize); + + // Infallibly allocate a new storage of the given size. + static Storage AllocBuffer(size_t aSize) { + auto ret = TryAllocBuffer(aSize); + if (!ret) { + NS_ABORT_OOM(aSize); + } + return std::move(ret.ref()); + } + + size_t mSize; + Storage mData; +}; + +} // namespace mozilla::ipc + +namespace IPC { + +template <> +struct ParamTraits<mozilla::ipc::BigBuffer> { + using paramType = mozilla::ipc::BigBuffer; + static void Write(MessageWriter* aWriter, paramType&& aParam); + static bool Read(MessageReader* aReader, paramType* aResult); +}; + +} // namespace IPC + +#endif // mozilla_BigBuffer_h |