/* -*- 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_SharedMemoryHandle_h
#define mozilla_ipc_SharedMemoryHandle_h
#include <utility>
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/UniquePtrExtensions.h"
namespace mozilla::ipc {
namespace shared_memory {
// Rust Bindgen code doesn't actually use these types, but `UniqueFileHandle`
// and `UniqueMachSendRight` aren't defined and some headers need to type check,
// so we define a dummy pointer type.
#if defined(RUST_BINDGEN)
using PlatformHandle =
void*;
#elif defined(XP_DARWIN)
using PlatformHandle = mozilla::UniqueMachSendRight;
#else
using PlatformHandle = mozilla::UniqueFileHandle;
#endif
struct Handle;
struct ReadOnlyHandle;
class HandleBase {
public:
/**
* The size of the shared memory region to which this handle refers.
*/
uint64_t Size()
const {
return mSize; }
/**
* Whether this shared memory handle is valid.
*/
bool IsValid()
const {
return (
bool)*
this; }
/**
* Whether this shared memory handle is valid.
*/
explicit operator bool()
const {
return (
bool)mHandle; }
friend class Platform;
friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::Handle>;
friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>;
protected:
HandleBase();
MOZ_IMPLICIT HandleBase(std::nullptr_t) {}
~HandleBase();
HandleBase(HandleBase&& aOther)
: mHandle(std::move(aOther.mHandle)),
mSize(std::exchange(aOther.mSize, 0)) {}
HandleBase&
operator=(HandleBase&& aOther);
HandleBase(
const HandleBase&) =
delete;
HandleBase&
operator=(
const HandleBase&) =
delete;
HandleBase Clone()
const;
template <
typename Derived>
Derived CloneAs()
const {
return Clone().ConvertTo<Derived>();
}
template <
typename Derived>
Derived ConvertTo() && {
Derived d;
static_cast<HandleBase&>(d) = std::move(*
this);
return d;
}
void ToMessageWriter(IPC::MessageWriter* aWriter) &&;
bool FromMessageReader(IPC::MessageReader* aReader);
private:
PlatformHandle mHandle = nullptr;
uint64_t mSize = 0;
};
/**
* A handle to a shared memory region.
*/
struct Handle : HandleBase {
/**
* Create an empty Handle.
*/
Handle() =
default;
MOZ_IMPLICIT Handle(std::nullptr_t) {}
/**
* Clone the handle.
*/
Handle Clone()
const {
return CloneAs<Handle>(); }
/**
* Map the shared memory region into memory.
*/
struct Mapping Map(
void* aFixedAddress = nullptr)
const;
};
/**
* A read-only handle to a shared memory region.
*/
struct ReadOnlyHandle : HandleBase {
/**
* Create an empty ReadOnlyHandle.
*/
ReadOnlyHandle() =
default;
MOZ_IMPLICIT ReadOnlyHandle(std::nullptr_t) {}
/**
* Clone the handle.
*/
ReadOnlyHandle Clone()
const {
return CloneAs<ReadOnlyHandle>(); }
/**
* Map the shared memory region into memory.
*/
struct ReadOnlyMapping Map(
void* aFixedAddress = nullptr)
const;
};
/**
* A freezable handle to a shared memory region.
*
* One cannot clone this handle, ensuring that at most one writable mapping
* exists. After freezing, no new writable mappings can be created.
*/
struct FreezableHandle : HandleBase {
/**
* Create an empty FreezableHandle.
*/
FreezableHandle() =
default;
MOZ_IMPLICIT FreezableHandle(std::nullptr_t) {}
~FreezableHandle();
FreezableHandle(FreezableHandle&&) =
default;
FreezableHandle&
operator=(FreezableHandle&&) =
default;
/**
* Convert to a normal handle if we will not freeze this handle.
*/
Handle WontFreeze() &&;
/**
* Freeze this handle, returning a read-only handle.
*/
ReadOnlyHandle Freeze() &&;
/**
* Map the shared memory region into memory.
*/
struct FreezableMapping Map(
void* aFixedAddress = nullptr) &&;
friend class Platform;
#if !
defined(XP_DARWIN) && !
defined(XP_WIN) && !
defined(ANDROID)
private:
PlatformHandle mFrozenFile;
#endif
};
/**
* Create a new shared memory region.
*/
Handle Create(uint64_t aSize);
/**
* Create a new freezable shared memory region.
*
* Freezable shared memory regions are distinguished by the property that there
* is guaranteed to be at most one writable mapping of the region at a time.
*
* Furthermore, a freezable shared memory region can be frozen while mapped. In
* this case, the mapping remains valid but there can be no new writable
* mappings.
*/
FreezableHandle CreateFreezable(uint64_t aSize);
}
// namespace shared_memory
using MutableSharedMemoryHandle = shared_memory::Handle;
using ReadOnlySharedMemoryHandle = shared_memory::ReadOnlyHandle;
using FreezableSharedMemoryHandle = shared_memory::FreezableHandle;
}
// namespace mozilla::ipc
namespace IPC {
template <>
struct ParamTraits<mozilla::ipc::shared_memory::Handle> {
static void Write(MessageWriter* aWriter,
mozilla::ipc::shared_memory::Handle&& aParam);
static bool Read(MessageReader* aReader,
mozilla::ipc::shared_memory::Handle* aResult);
};
template <>
struct ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle> {
static void Write(MessageWriter* aWriter,
mozilla::ipc::shared_memory::ReadOnlyHandle&& aParam);
static bool Read(MessageReader* aReader,
mozilla::ipc::shared_memory::ReadOnlyHandle* aResult);
};
}
// namespace IPC
#endif