diff options
Diffstat (limited to 'ipc/glue/RawShmem.cpp')
-rw-r--r-- | ipc/glue/RawShmem.cpp | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/ipc/glue/RawShmem.cpp b/ipc/glue/RawShmem.cpp new file mode 100644 index 0000000000..bfb47c0832 --- /dev/null +++ b/ipc/glue/RawShmem.cpp @@ -0,0 +1,114 @@ +/* -*- 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::SharedMemoryBasic::NULLHandle()), mSize(0) {} + +UnsafeSharedMemoryHandle::UnsafeSharedMemoryHandle( + UnsafeSharedMemoryHandle&& aOther) noexcept + : mHandle(std::move(aOther.mHandle)), mSize(aOther.mSize) { + aOther.mHandle = ipc::SharedMemoryBasic::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::SharedMemoryBasic::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::SharedMemoryBasic> shm = MakeAndAddRef<ipc::SharedMemoryBasic>(); + if (NS_WARN_IF(!shm->Create(aSize)) || NS_WARN_IF(!shm->Map(aSize))) { + return Nothing(); + } + + // TODO(bug 1797039): At the moment the handle/mapping distinction is + // implemented on top of a single class SharedMemoryBasic. It leads to a few + // awkward or sub-optimal things such as how the following few lines clone + // then close the handle. It would be better to separate the underlying + // implementation or steal the handle to avoid cloning it. + auto handle = shm->CloneHandle(); + + shm->CloseHandle(); + auto size = shm->Size(); + + return Some(std::make_pair(UnsafeSharedMemoryHandle(std::move(handle), size), + WritableSharedMemoryMapping(std::move(shm)))); +} + +WritableSharedMemoryMapping::WritableSharedMemoryMapping( + RefPtr<ipc::SharedMemoryBasic>&& aRef) + : mRef(aRef) {} + +Maybe<WritableSharedMemoryMapping> WritableSharedMemoryMapping::Open( + UnsafeSharedMemoryHandle aHandle) { + if (aHandle.mSize == 0) { + return Some(WritableSharedMemoryMapping(nullptr)); + } + + RefPtr<ipc::SharedMemoryBasic> shm = MakeAndAddRef<ipc::SharedMemoryBasic>(); + 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 |