// 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_