Bug 1942129 pt4b - Remove use of RawShmem r=ipc-reviewers,nika,webgpu-reviewers,nical

Differential Revision: https://phabricator.services.mozilla.com/D236749
This commit is contained in:
Alex Franchuk
2025-03-03 19:53:19 +00:00
parent e343bd6f6c
commit 57e4ff560c
14 changed files with 80 additions and 359 deletions

View File

@@ -42,11 +42,10 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Buffer)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
Buffer::Buffer(Device* const aParent, RawId aId, BufferAddress aSize,
uint32_t aUsage, ipc::WritableSharedMemoryMapping&& aShmem)
uint32_t aUsage, ipc::SharedMemoryMapping&& aShmem)
: ChildOf(aParent), mId(aId), mSize(aSize), mUsage(aUsage) {
mozilla::HoldJSObjects(this);
mShmem =
std::make_shared<ipc::WritableSharedMemoryMapping>(std::move(aShmem));
mShmem = std::make_shared<ipc::SharedMemoryMapping>(std::move(aShmem));
MOZ_ASSERT(mParent);
}
@@ -63,14 +62,14 @@ already_AddRefed<Buffer> Buffer::Create(Device* aDevice, RawId aDeviceId,
if (!aDevice->IsBridgeAlive()) {
// Create and return an invalid Buffer.
RefPtr<Buffer> buffer = new Buffer(aDevice, bufferId, aDesc.mSize, 0,
ipc::WritableSharedMemoryMapping());
RefPtr<Buffer> buffer =
new Buffer(aDevice, bufferId, aDesc.mSize, 0, nullptr);
buffer->mValid = false;
return buffer.forget();
}
auto handle = ipc::UnsafeSharedMemoryHandle();
auto mapping = ipc::WritableSharedMemoryMapping();
ipc::MutableSharedMemoryHandle handle;
ipc::SharedMemoryMapping mapping;
bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE |
dom::GPUBufferUsage_Binding::MAP_READ);
@@ -85,17 +84,18 @@ already_AddRefed<Buffer> Buffer::Create(Device* aDevice, RawId aDeviceId,
size_t size = checked.value();
if (size > 0 && size < maxSize) {
auto maybeShmem = ipc::UnsafeSharedMemoryHandle::CreateAndMap(size);
if (maybeShmem.isSome()) {
handle = ipc::shared_memory::Create(size);
mapping = handle.Map();
if (handle && mapping) {
allocSucceeded = true;
handle = std::move(maybeShmem.ref().first);
mapping = std::move(maybeShmem.ref().second);
MOZ_RELEASE_ASSERT(mapping.Size() >= size);
// zero out memory
memset(mapping.Bytes().data(), 0, size);
memset(mapping.Address(), 0, size);
} else {
handle = nullptr;
mapping = nullptr;
}
}
@@ -259,8 +259,7 @@ already_AddRefed<dom::Promise> Buffer::MapAsync(
static void ExternalBufferFreeCallback(void* aContents, void* aUserData) {
Unused << aContents;
auto shm = static_cast<std::shared_ptr<ipc::WritableSharedMemoryMapping>*>(
aUserData);
auto shm = static_cast<std::shared_ptr<ipc::SharedMemoryMapping>*>(aUserData);
delete shm;
}
@@ -353,8 +352,8 @@ void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset,
// unfortunately necessary: `JS::BufferContentsDeleter` requires that its
// `userData` be a `void*`, and while `shared_ptr` can't be inter-converted
// with `void*` (it's actually two pointers), `shared_ptr*` obviously can.
std::shared_ptr<ipc::WritableSharedMemoryMapping>* data =
new std::shared_ptr<ipc::WritableSharedMemoryMapping>(mShmem);
std::shared_ptr<ipc::SharedMemoryMapping>* data =
new std::shared_ptr<ipc::SharedMemoryMapping>(mShmem);
// 4. Let `view` be (potentially fallible operation follows) create an
// `ArrayBuffer` of size `rangeSize`, but with its pointer mutably
@@ -366,7 +365,8 @@ void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset,
// range for `size_t` before any conversion is performed.
const auto checkedSize = CheckedInt<size_t>(rangeSize.value()).value();
const auto checkedOffset = CheckedInt<size_t>(offset.value()).value();
const auto span = (*data)->Bytes().Subspan(checkedOffset, checkedSize);
const auto span =
(*data)->DataAsSpan<uint8_t>().Subspan(checkedOffset, checkedSize);
UniquePtr<void, JS::BufferContentsDeleter> contents{
span.data(), {&ExternalBufferFreeCallback, data}};
JS::Rooted<JSObject*> view(
@@ -431,7 +431,7 @@ void Buffer::Unmap(JSContext* aCx, ErrorResult& aRv) {
// We get here if the buffer was mapped at creation without map flags.
// It won't be possible to map the buffer again so we can get rid of
// our shmem on this side.
mShmem = std::make_shared<ipc::WritableSharedMemoryMapping>();
mShmem = std::make_shared<ipc::SharedMemoryMapping>();
}
if (!GetDevice().IsLost()) {

View File

@@ -8,10 +8,10 @@
#include "js/RootingAPI.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/webgpu/WebGPUTypes.h"
#include "nsTArray.h"
#include "ObjectModel.h"
#include "mozilla/ipc/RawShmem.h"
#include <memory>
namespace mozilla {
@@ -112,7 +112,7 @@ class Buffer final : public ObjectBase, public ChildOf<Device> {
private:
Buffer(Device* const aParent, RawId aId, BufferAddress aSize, uint32_t aUsage,
ipc::WritableSharedMemoryMapping&& aShmem);
ipc::SharedMemoryMapping&& aShmem);
virtual ~Buffer();
Device& GetDevice() { return *mParent; }
void Cleanup();
@@ -143,10 +143,10 @@ class Buffer final : public ObjectBase, public ChildOf<Device> {
// and destroyed when we first unmap the buffer, by clearing this
// `shared_ptr`.
//
// Otherwise, this points to `WritableSharedMemoryMapping()` (the
// default constructor), a zero-length mapping that doesn't point to
// any shared memory.
std::shared_ptr<ipc::WritableSharedMemoryMapping> mShmem;
// Otherwise, this points to `SharedMemoryMapping()` (the default
// constructor), a zero-length mapping that doesn't point to any shared
// memory.
std::shared_ptr<ipc::SharedMemoryMapping> mShmem;
};
} // namespace webgpu

View File

@@ -20,6 +20,8 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WebGLTexelConversions.h"
#include "mozilla/dom/WebGLTypes.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "nsLayoutUtils.h"
#include "Utility.h"
@@ -118,16 +120,17 @@ void Queue::WriteBuffer(const Buffer& aBuffer, uint64_t aBufferOffset,
return;
}
auto alloc = mozilla::ipc::UnsafeSharedMemoryHandle::CreateAndMap(size);
if (alloc.isNothing()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
mozilla::ipc::MutableSharedMemoryHandle handle;
if (size != 0) {
handle = mozilla::ipc::shared_memory::Create(size);
auto mapping = handle.Map();
if (!handle || !mapping) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
memcpy(mapping.DataAs<uint8_t>(), aData.Elements() + offset, size);
}
auto handle = std::move(alloc.ref().first);
auto mapping = std::move(alloc.ref().second);
memcpy(mapping.Bytes().data(), aData.Elements() + offset, size);
ipc::ByteBuf bb;
ffi::wgpu_queue_write_buffer(aBuffer.mId, aBufferOffset, ToFFI(&bb));
mBridge->SendQueueWriteAction(mId, mParent->mId, std::move(bb),
@@ -161,18 +164,19 @@ void Queue::WriteTexture(const dom::GPUTexelCopyTextureInfo& aDestination,
}
const auto size = checkedSize.value();
auto alloc = mozilla::ipc::UnsafeSharedMemoryHandle::CreateAndMap(size);
if (alloc.isNothing()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
mozilla::ipc::MutableSharedMemoryHandle handle;
if (size != 0) {
handle = mozilla::ipc::shared_memory::Create(size);
auto mapping = handle.Map();
if (!handle || !mapping) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
memcpy(mapping.DataAs<uint8_t>(), aData.Elements() + aDataLayout.mOffset,
size);
}
auto handle = std::move(alloc.ref().first);
auto mapping = std::move(alloc.ref().second);
memcpy(mapping.Bytes().data(), aData.Elements() + aDataLayout.mOffset,
size);
ipc::ByteBuf bb;
ffi::wgpu_queue_write_texture(copyView, dataLayout, extent, ToFFI(&bb));
mBridge->SendQueueWriteAction(mId, mParent->mId, std::move(bb),
@@ -395,18 +399,15 @@ void Queue::CopyExternalImageToTexture(
return;
}
auto alloc = mozilla::ipc::UnsafeSharedMemoryHandle::CreateAndMap(
dstByteLength.value());
if (alloc.isNothing()) {
auto handle = mozilla::ipc::shared_memory::Create(dstByteLength.value());
auto mapping = handle.Map();
if (!handle || !mapping) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
auto handle = std::move(alloc.ref().first);
auto mapping = std::move(alloc.ref().second);
const int32_t pixelSize = gfx::BytesPerPixel(surfaceFormat);
auto* dstBegin = mapping.Bytes().data();
auto* dstBegin = mapping.DataAs<uint8_t>();
const auto* srcBegin =
map.GetData() + srcOriginX * pixelSize + srcOriginY * map.GetStride();
const auto srcOriginPos = gl::OriginPos::TopLeft;

View File

@@ -17,7 +17,7 @@ using mozilla::dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h
using mozilla::dom::GPUBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
using mozilla::webgpu::PopErrorScopeResult from "mozilla/webgpu/WebGPUTypes.h";
using mozilla::webgpu::WebGPUCompilationMessage from "mozilla/webgpu/WebGPUTypes.h";
[MoveOnly] using class mozilla::ipc::UnsafeSharedMemoryHandle from "mozilla/ipc/RawShmem.h";
[MoveOnly] using mozilla::ipc::MutableSharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
include "mozilla/ipc/ByteBufUtils.h";
@@ -48,7 +48,7 @@ parent:
async ComputePass(RawId selfId, RawId aDeviceId, ByteBuf buf);
async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId);
async DeviceCreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, UnsafeSharedMemoryHandle shm);
async DeviceCreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, MutableSharedMemoryHandle shm);
async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId aAdapterId) returns (ByteBuf byteBuf);
async AdapterRequestDevice(
@@ -77,7 +77,8 @@ parent:
async RenderBundleDrop(RawId selfId);
async QueueSubmit(RawId selfId, RawId aDeviceId, RawId[] commandBuffers, RawId[] textureIds);
async QueueOnSubmittedWorkDone(RawId selfId) returns (void_t ok);
async QueueWriteAction(RawId selfId, RawId aDeviceId, ByteBuf buf, UnsafeSharedMemoryHandle shmem);
// In the case of a zero-sized write action, `shmem` will be an invalid handle.
async QueueWriteAction(RawId selfId, RawId aDeviceId, ByteBuf buf, MutableSharedMemoryHandle shmem);
async BindGroupLayoutDrop(RawId selfId);
async PipelineLayoutDrop(RawId selfId);

View File

@@ -25,7 +25,6 @@
#include "PipelineLayout.h"
#include "Sampler.h"
#include "CompilationInfo.h"
#include "mozilla/ipc/RawShmem.h"
#include "Utility.h"
#include <utility>

View File

@@ -12,9 +12,6 @@
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla {
namespace ipc {
class UnsafeSharedMemoryHandle;
} // namespace ipc
namespace dom {
struct GPURequestAdapterOptions;
} // namespace dom

View File

@@ -549,11 +549,10 @@ WebGPUParent::BufferMapData* WebGPUParent::GetBufferMapData(RawId aBufferId) {
ipc::IPCResult WebGPUParent::RecvDeviceCreateBuffer(
RawId aDeviceId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc,
ipc::UnsafeSharedMemoryHandle&& aShmem) {
ipc::MutableSharedMemoryHandle&& aShmem) {
webgpu::StringHelper label(aDesc.mLabel);
auto shmem =
ipc::WritableSharedMemoryMapping::Open(std::move(aShmem)).value();
auto shmem = aShmem.Map();
bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE |
dom::GPUBufferUsage_Binding::MAP_READ);
@@ -664,7 +663,7 @@ void WebGPUParent::MapCallback(uint8_t* aUserData,
MOZ_RELEASE_ASSERT(mapData->mShmem.Size() >= offset + size);
if (src.ptr != nullptr && src.length >= size) {
auto dst = mapData->mShmem.Bytes().Subspan(offset, size);
auto dst = mapData->mShmem.DataAsSpan<uint8_t>().Subspan(offset, size);
memcpy(dst.data(), src.ptr, size);
}
}
@@ -747,7 +746,7 @@ ipc::IPCResult WebGPUParent::RecvBufferUnmap(RawId aDeviceId, RawId aBufferId,
MOZ_RELEASE_ASSERT(offset <= shmSize);
MOZ_RELEASE_ASSERT(size <= shmSize - offset);
auto src = mapData->mShmem.Bytes().Subspan(offset, size);
auto src = mapData->mShmem.DataAsSpan<uint8_t>().Subspan(offset, size);
memcpy(mapped.ptr, src.data(), size);
}
@@ -912,14 +911,15 @@ ipc::IPCResult WebGPUParent::RecvQueueOnSubmittedWorkDone(
ipc::IPCResult WebGPUParent::RecvQueueWriteAction(
RawId aQueueId, RawId aDeviceId, const ipc::ByteBuf& aByteBuf,
ipc::UnsafeSharedMemoryHandle&& aShmem) {
auto mapping =
ipc::WritableSharedMemoryMapping::Open(std::move(aShmem)).value();
ipc::MutableSharedMemoryHandle&& aShmem) {
// `aShmem` may be an invalid handle, however this will simply result in an
// invalid mapping with 0 size, which is used safely below.
auto mapping = aShmem.Map();
ErrorBuffer error;
ffi::wgpu_server_queue_write_action(mContext.get(), aQueueId,
ToFFI(&aByteBuf), mapping.Bytes().data(),
mapping.Size(), error.ToFFI());
ffi::wgpu_server_queue_write_action(
mContext.get(), aQueueId, ToFFI(&aByteBuf), mapping.DataAs<uint8_t>(),
mapping.Size(), error.ToFFI());
ForwardError(aDeviceId, error);
return IPC_OK();
}

View File

@@ -9,10 +9,10 @@
#include <unordered_map>
#include "mozilla/WeakPtr.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/webgpu/ffi/wgpu.h"
#include "mozilla/webgpu/PWebGPUParent.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/ipc/RawShmem.h"
#include "WebGPUTypes.h"
#include "base/timer.h"
@@ -56,9 +56,9 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
ipc::IPCResult RecvAdapterDrop(RawId aAdapterId);
ipc::IPCResult RecvDeviceDestroy(RawId aDeviceId);
ipc::IPCResult RecvDeviceDrop(RawId aDeviceId);
ipc::IPCResult RecvDeviceCreateBuffer(RawId aDeviceId, RawId aBufferId,
dom::GPUBufferDescriptor&& aDesc,
ipc::UnsafeSharedMemoryHandle&& aShmem);
ipc::IPCResult RecvDeviceCreateBuffer(
RawId aDeviceId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc,
ipc::MutableSharedMemoryHandle&& aShmem);
ipc::IPCResult RecvBufferMap(RawId aDeviceId, RawId aBufferId, uint32_t aMode,
uint64_t aOffset, uint64_t size,
BufferMapResolver&& aResolver);
@@ -83,7 +83,7 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
RawId aQueueId, std::function<void(mozilla::void_t)>&& aResolver);
ipc::IPCResult RecvQueueWriteAction(RawId aQueueId, RawId aDeviceId,
const ipc::ByteBuf& aByteBuf,
ipc::UnsafeSharedMemoryHandle&& aShmem);
ipc::MutableSharedMemoryHandle&& aShmem);
ipc::IPCResult RecvBindGroupLayoutDrop(RawId aBindGroupLayoutId);
ipc::IPCResult RecvPipelineLayoutDrop(RawId aPipelineLayoutId);
ipc::IPCResult RecvBindGroupDrop(RawId aBindGroupId);
@@ -141,7 +141,7 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
void ActorDestroy(ActorDestroyReason aWhy) override;
struct BufferMapData {
ipc::WritableSharedMemoryMapping mShmem;
ipc::SharedMemoryMapping mShmem;
// True if buffer's usage has MAP_READ or MAP_WRITE set.
bool mHasMapFlags;
uint64_t mMappedOffset;

View File

@@ -2549,7 +2549,13 @@ pub unsafe extern "C" fn wgpu_server_queue_write_action(
mut error_buf: ErrorBuffer,
) {
let action: QueueWriteAction = bincode::deserialize(byte_buf.as_slice()).unwrap();
let data = slice::from_raw_parts(data, data_length);
// It is undefined behavior to pass a null pointer to `slice::from_raw_parts`, so in the case
// of a null pointer (which occurs if `data_length` is 0), we use a dangling pointer.
let data = ptr::NonNull::new(data as *mut u8).unwrap_or_else(|| {
assert!(data_length == 0);
ptr::NonNull::dangling()
});
let data = slice::from_raw_parts(data.as_ptr(), data_length);
let result = match action {
QueueWriteAction::Buffer { dst, offset } => {
global.queue_write_buffer(self_id, dst, offset, data)

View File

@@ -1,108 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "RawShmem.h"
#include "mozilla/ipc/ProtocolUtils.h"
namespace mozilla::ipc {
UnsafeSharedMemoryHandle::UnsafeSharedMemoryHandle()
: mHandle(ipc::SharedMemory::NULLHandle()), mSize(0) {}
UnsafeSharedMemoryHandle::UnsafeSharedMemoryHandle(
UnsafeSharedMemoryHandle&& aOther) noexcept
: mHandle(std::move(aOther.mHandle)), mSize(aOther.mSize) {
aOther.mHandle = ipc::SharedMemory::NULLHandle();
aOther.mSize = 0;
}
UnsafeSharedMemoryHandle& UnsafeSharedMemoryHandle::operator=(
UnsafeSharedMemoryHandle&& aOther) noexcept {
if (this == &aOther) {
return *this;
}
mHandle = std::move(aOther.mHandle);
mSize = aOther.mSize;
aOther.mHandle = ipc::SharedMemory::NULLHandle();
aOther.mSize = 0;
return *this;
}
Maybe<std::pair<UnsafeSharedMemoryHandle, WritableSharedMemoryMapping>>
UnsafeSharedMemoryHandle::CreateAndMap(size_t aSize) {
if (aSize == 0) {
return Some(std::make_pair(UnsafeSharedMemoryHandle(),
WritableSharedMemoryMapping()));
}
RefPtr<ipc::SharedMemory> shm = MakeAndAddRef<ipc::SharedMemory>();
if (NS_WARN_IF(!shm->Create(aSize)) || NS_WARN_IF(!shm->Map(aSize))) {
return Nothing();
}
auto handle = shm->TakeHandle();
auto size = shm->Size();
return Some(std::make_pair(UnsafeSharedMemoryHandle(std::move(handle), size),
WritableSharedMemoryMapping(std::move(shm))));
}
WritableSharedMemoryMapping::WritableSharedMemoryMapping(
RefPtr<ipc::SharedMemory>&& aRef)
: mRef(aRef) {}
Maybe<WritableSharedMemoryMapping> WritableSharedMemoryMapping::Open(
UnsafeSharedMemoryHandle aHandle) {
if (aHandle.mSize == 0) {
return Some(WritableSharedMemoryMapping(nullptr));
}
RefPtr<ipc::SharedMemory> shm = MakeAndAddRef<ipc::SharedMemory>();
if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle.mHandle),
ipc::SharedMemory::RightsReadWrite)) ||
NS_WARN_IF(!shm->Map(aHandle.mSize))) {
return Nothing();
}
shm->CloseHandle();
return Some(WritableSharedMemoryMapping(std::move(shm)));
}
size_t WritableSharedMemoryMapping::Size() const {
if (!mRef) {
return 0;
}
return mRef->Size();
}
Span<uint8_t> WritableSharedMemoryMapping::Bytes() {
if (!mRef) {
return Span<uint8_t>();
}
uint8_t* mem = static_cast<uint8_t*>(mRef->Memory());
return Span(mem, mRef->Size());
}
} // namespace mozilla::ipc
namespace IPC {
auto ParamTraits<mozilla::ipc::UnsafeSharedMemoryHandle>::Write(
IPC::MessageWriter* aWriter, paramType&& aVar) -> void {
IPC::WriteParam(aWriter, std::move(aVar.mHandle));
IPC::WriteParam(aWriter, aVar.mSize);
}
auto ParamTraits<mozilla::ipc::UnsafeSharedMemoryHandle>::Read(
IPC::MessageReader* aReader, paramType* aVar) -> bool {
return IPC::ReadParam(aReader, &aVar->mHandle) &&
IPC::ReadParam(aReader, &aVar->mSize);
}
} // namespace IPC

View File

@@ -1,114 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_RAWSHMEM_H_
#define MOZILLA_IPC_RAWSHMEM_H_
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/Span.h"
#include <utility>
namespace mozilla::ipc {
class WritableSharedMemoryMapping;
/// A handle to shared memory.
///
/// See the doc comment for `WritableSharedMemoryMapping` below.
class UnsafeSharedMemoryHandle {
friend class WritableSharedMemoryMapping;
friend struct IPC::ParamTraits<UnsafeSharedMemoryHandle>;
public:
UnsafeSharedMemoryHandle();
UnsafeSharedMemoryHandle(UnsafeSharedMemoryHandle&& aOther) noexcept;
UnsafeSharedMemoryHandle& operator=(
UnsafeSharedMemoryHandle&& aOther) noexcept;
/// Attempts to allocate a shmem.
///
/// Returns `Nothing()` if allocation fails.
/// If `aSize` is zero, a valid empty WritableSharedMemoryMapping is returned.
static Maybe<std::pair<UnsafeSharedMemoryHandle, WritableSharedMemoryMapping>>
CreateAndMap(size_t aSize);
private:
UnsafeSharedMemoryHandle(SharedMemory::Handle&& aHandle, uint64_t aSize)
: mHandle(std::move(aHandle)), mSize(aSize) {}
SharedMemory::Handle mHandle;
uint64_t mSize;
};
/// A Shared memory buffer mapping.
///
/// Unlike `ipc::Shmem`, the underlying shared memory buffer on each side of
/// the process boundary is only deallocated with there respective
/// `WritableSharedMemoryMapping`.
///
/// ## Usage
///
/// Typical usage goes as follows:
/// - Allocate the memory using `UnsafeSharedMemoryHandle::Create`, returning a
/// handle and a mapping.
/// - Send the handle to the other process using an IPDL message.
/// - On the other process, map the shared memory by creating
/// WritableSharedMemoryMapping via `WritableSharedMemoryMapping::Open` and
/// the received handle.
///
/// Do not send the shared memory handle again, it is only intended to establish
/// the mapping on each side during initialization. The user of this class is
/// responsible for managing the lifetime of the buffers on each side, as well
/// as their identity, by for example storing them in hash map and referring to
/// them via IDs in IPDL message if need be.
///
/// ## Empty shmems
///
/// An empty WritableSharedMemoryMapping is one that was created with size zero.
/// It is analogous to a null RefPtr. It can be used like a non-empty shmem,
/// including sending the handle and openning it on another process (resulting
/// in an empty mapping on the other side).
class WritableSharedMemoryMapping {
friend class UnsafeSharedMemoryHandle;
public:
WritableSharedMemoryMapping() = default;
WritableSharedMemoryMapping(WritableSharedMemoryMapping&& aMoved) = default;
WritableSharedMemoryMapping& operator=(WritableSharedMemoryMapping&& aMoved) =
default;
/// Open the shmem and immediately close the handle.
static Maybe<WritableSharedMemoryMapping> Open(
UnsafeSharedMemoryHandle aHandle);
// Returns the size in bytes.
size_t Size() const;
// Returns the shared memory as byte range.
Span<uint8_t> Bytes();
private:
explicit WritableSharedMemoryMapping(
RefPtr<mozilla::ipc::SharedMemory>&& aRef);
RefPtr<mozilla::ipc::SharedMemory> mRef;
};
} // namespace mozilla::ipc
namespace IPC {
template <>
struct ParamTraits<mozilla::ipc::UnsafeSharedMemoryHandle> {
typedef mozilla::ipc::UnsafeSharedMemoryHandle paramType;
static void Write(IPC::MessageWriter* aWriter, paramType&& aVar);
static bool Read(IPC::MessageReader* aReader, paramType* aVar);
};
} // namespace IPC
#endif

View File

@@ -52,7 +52,6 @@ EXPORTS.mozilla.ipc += [
"ProtocolMessageUtils.h",
"ProtocolUtils.h",
"RandomAccessStreamUtils.h",
"RawShmem.h",
"RustMessageUtils.h",
"ScopedPort.h",
"SerializedStructuredCloneBuffer.h",
@@ -194,7 +193,6 @@ UNIFIED_SOURCES += [
"ProcessUtils_common.cpp",
"ProtocolUtils.cpp",
"RandomAccessStreamUtils.cpp",
"RawShmem.cpp",
"ScopedPort.cpp",
"SerializedStructuredCloneBuffer.cpp",
"SharedMemory.cpp",

View File

@@ -1,58 +0,0 @@
/* -*- 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/. */
#include "chrome/common/ipc_message.h"
#include "chrome/common/ipc_message_utils.h"
#include "gtest/gtest.h"
#include "mozilla/RandomNum.h"
#include "mozilla/ipc/RawShmem.h"
namespace mozilla::ipc {
static bool SerializeAndDeserialize(UnsafeSharedMemoryHandle&& aIn,
UnsafeSharedMemoryHandle* aOut) {
IPC::Message msg(MSG_ROUTING_NONE, 0);
{
IPC::MessageWriter writer(msg);
IPC::WriteParam(&writer, std::move(aIn));
}
IPC::MessageReader reader(msg);
return IPC::ReadParam(&reader, aOut);
}
void TestUnsafeSharedMemoryHandle(size_t aSize) {
auto maybeHandle = UnsafeSharedMemoryHandle::CreateAndMap(aSize);
ASSERT_TRUE(maybeHandle);
auto [handle, mapping] = maybeHandle.extract();
EXPECT_EQ(mapping.Size(), aSize);
auto inBytes = mapping.Bytes();
for (size_t i = 0; i < aSize; ++i) {
inBytes[i] = static_cast<uint8_t>(i % 255);
}
UnsafeSharedMemoryHandle out;
ASSERT_TRUE(SerializeAndDeserialize(std::move(handle), &out));
auto mapping2 = WritableSharedMemoryMapping::Open(std::move(out)).value();
EXPECT_EQ(mapping2.Size(), aSize);
auto outBytes = mapping2.Bytes();
for (size_t i = 0; i < aSize; ++i) {
EXPECT_EQ(outBytes[i], static_cast<uint8_t>(i % 255));
}
}
TEST(UnsafeSharedMemoryHandle, Empty)
{ TestUnsafeSharedMemoryHandle(0); }
TEST(UnsafeSharedMemoryHandle, SmallSize)
{ TestUnsafeSharedMemoryHandle(2048); }
} // namespace mozilla::ipc

View File

@@ -12,7 +12,6 @@ SOURCES += [
"TestLogging.cpp",
"TestRandomAccessStreamUtils.cpp",
"TestSharedMemory.cpp",
"TestUnsafeSharedMemoryHandle.cpp",
]
include("/ipc/chromium/chromium-config.mozbuild")