chromium/base/memory/structured_shared_memory.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MEMORY_STRUCTURED_SHARED_MEMORY_H_
#define BASE_MEMORY_STRUCTURED_SHARED_MEMORY_H_

#include <atomic>
#include <memory>
#include <optional>
#include <utility>

#include "base/check.h"
#include "base/containers/span.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/shared_memory_mapper.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/shared_memory_safety_checker.h"

namespace base {

// `StructuredSharedMemory` wraps a handle to a shared memory region, and a
// writable mapping of that region sized and aligned to hold a type `T`. Only
// the process that creates the memory region can write to it, but it can pass
// read-only handles to other processes for reading.
//
// The caller must ensure that reads from other processes are synchronized with
// writes to the memory, such as by using a shared lock or storing std::atomic
// types in the memory region. As a convenience, `AtomicSharedMemory<T>` is an
// alias for `StructuredSharedMemory<std::atomic<T>>`.
//
// If `T` is a struct, the caller should ensure that it has no padding that
// could leak information, and that each member is safe to use over shared
// memory. SharedMemorySafetyChecker is helpful for this.
//
// Example of use:
//
// In the browser process:
//
//   optional<AtomicSharedMemory<TimeTicks>> shared_timestamp_memory =
//       AtomicSharedMemory<TimeTicks>::Create(TimeTicks::Now());
//   if (!shared_timestamp_memory) {
//     HandleFailedToMapMemoryError();
//     return;
//   }
//   PassRegionHandleToChild(shared_timestamp_memory->TakeReadOnlyRegion());
//   ...
//   // When an event occurs:
//   shared_timestamp_memory->WritableRef().store(TimeTicks::Now(),
//       std::memory_order_relaxed);
//   ...
//   // Destroying the StructuredSharedMemory will unmap the memory from this
//   // process. The child will still have a mapping.
//   shared_timestamp_memory.reset();
//
// In the child process:
//
//   optional<AtomicSharedMemory<TimeTicks>::ReadOnlyMapping>
//       shared_timestamp_mapping =
//           AtomicSharedMemory<TimeTicks>::MapReadOnlyRegion(region_handle);
//   if (!shared_timestamp_mapping) {
//     HandleFailedToMapMemoryError();
//     return;
//   }
//   ...
//   // Periodically check the timestamp.
//   TimeTicks event_time = shared_timestamp_mapping->ReadOnlyRef().load(
//        std::memory_order_relaxed);
//   ...
//
// TODO(crbug.com/357945779): Find a way to automatically validate struct
// members, or find another way to safely store multiple types in the same
// region.
//
// TODO(crbug.com/357945779): Allow multiple copies of T, with accessors that
// return span<T>.
template <typename T>
class StructuredSharedMemory {};

// A read-only mapping of a shared memory region, sized and aligned to hold a
// list types `T`. This is intended for use with a ReadOnlySharedMemoryRegion
// created by StructuredSharedMemory<T>.
//
// Although this view of the memory is read-only, the memory can be modified by
// the process holding the StructuredSharedMemory at any time. So all reads must
// be synchronized with the writes, such as by using a shared lock or storing
// std::atomic types in the memory region.
template <typename T>
class StructuredSharedMemory<T>::ReadOnlyMapping {};

// Convenience alias for a StructuredSharedMemory region containing a
// std::atomic type.
AtomicSharedMemory;

// Implementation.

namespace internal {

// CHECK's that a mapping of length `size` located at `ptr` is aligned correctly
// and large enough to hold a T, and that T is safe to use over shared memory.
template <typename T>
  requires(subtle::AllowedOverSharedMemory<T>)
void AssertSafeToMap(base::span<const uint8_t> mapped_span) {}

}  // namespace internal

// static
template <typename T>
std::optional<StructuredSharedMemory<T>> StructuredSharedMemory<T>::Create() {}

// static
template <typename T>
template <typename U>
std::optional<StructuredSharedMemory<T>> StructuredSharedMemory<T>::Create(
    U&& initial_value) {}

// static
template <typename T>
std::optional<StructuredSharedMemory<T>>
StructuredSharedMemory<T>::CreateWithCustomMapper(SharedMemoryMapper* mapper) {}

// static
template <typename T>
template <typename U>
std::optional<StructuredSharedMemory<T>>
StructuredSharedMemory<T>::CreateWithCustomMapper(U&& initial_value,
                                                  SharedMemoryMapper* mapper) {}

// static
template <typename T>
std::optional<typename StructuredSharedMemory<T>::ReadOnlyMapping>
StructuredSharedMemory<T>::MapReadOnlyRegion(ReadOnlySharedMemoryRegion region,
                                             SharedMemoryMapper* mapper) {}

}  // namespace base

#endif  // BASE_MEMORY_STRUCTURED_SHARED_MEMORY_H_