// Copyright 2015 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif #ifndef BASE_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_ #define BASE_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_ #include <stdint.h> #include <atomic> #include <memory> #include <string_view> #include <type_traits> #include "base/atomicops.h" #include "base/base_export.h" #include "base/check.h" #include "base/check_op.h" #include "base/containers/span.h" #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr_exclusion.h" #include "base/memory/shared_memory_mapping.h" #include "build/build_config.h" namespace metrics { class FileMetricsProvider; } namespace base { class HistogramBase; class MemoryMappedFile; // Simple allocator for pieces of a memory block that may be persistent // to some storage or shared across multiple processes. This class resides // under base/metrics because it was written for that purpose. It is, // however, fully general-purpose and can be freely moved to base/memory // if other uses are found. // // This class provides for thread-secure (i.e. safe against other threads // or processes that may be compromised and thus have malicious intent) // allocation of memory within a designated block and also a mechanism by // which other threads can learn of these allocations. // // There is (currently) no way to release an allocated block of data because // doing so would risk invalidating pointers held by other processes and // greatly complicate the allocation algorithm. // // Construction of this object can accept new, clean (i.e. zeroed) memory // or previously initialized memory. In the first case, construction must // be allowed to complete before letting other allocators attach to the same // segment. In other words, don't share the segment until at least one // allocator has been attached to it. // // Note that memory not in active use is not accessed so it is possible to // use virtual memory, including memory-mapped files, as backing storage with // the OS "pinning" new (zeroed) physical RAM pages only as they are needed. // // OBJECTS: Although the allocator can be used in a "malloc" sense, fetching // character arrays and manipulating that memory manually, the better way is // generally to use the "object" methods to create and manage allocations. In // this way the sizing, type-checking, and construction are all automatic. For // this to work, however, every type of stored object must define two public // "constexpr" values, kPersistentTypeId and kExpectedInstanceSize, as such: // // struct MyPersistentObjectType { // // SHA1(MyPersistentObjectType): Increment this if structure changes! // static constexpr uint32_t kPersistentTypeId = 0x3E15F6DE + 1; // // // Expected size for 32/64-bit check. Update this if structure changes! // static constexpr size_t kExpectedInstanceSize = 20; // // ... // }; // // kPersistentTypeId: This value is an arbitrary identifier that allows the // identification of these objects in the allocator, including the ability // to find them via iteration. The number is arbitrary but using the first // four bytes of the SHA1 hash of the type name means that there shouldn't // be any conflicts with other types that may also be stored in the memory. // The fully qualified name (e.g. base::debug::MyPersistentObjectType) could // be used to generate the hash if the type name seems common. Use a command // like this to get the hash: echo -n "MyPersistentObjectType" | sha1sum // If the structure layout changes, ALWAYS increment this number so that // newer versions of the code don't try to interpret persistent data written // by older versions with a different layout. // // kExpectedInstanceSize: This value is the hard-coded number that matches // what sizeof(T) would return. By providing it explicitly, the allocator can // verify that the structure is compatible between both 32-bit and 64-bit // versions of the code. // // Using New manages the memory and then calls the default constructor for the // object. Given that objects are persistent, no destructor is ever called // automatically though a caller can explicitly call Delete to destruct it and // change the type to something indicating it is no longer in use. // // Though persistent memory segments are transferrable between programs built // for different natural word widths, they CANNOT be exchanged between CPUs // of different endianess. Attempts to do so will simply see the existing data // as corrupt and refuse to access any of it. class BASE_EXPORT PersistentMemoryAllocator { … }; // This allocator uses a local memory block it allocates from the general // heap. It is generally used when some kind of "death rattle" handler will // save the contents to persistent storage during process shutdown. It is // also useful for testing. class BASE_EXPORT LocalPersistentMemoryAllocator : public PersistentMemoryAllocator { … }; // This allocator takes a writable shared memory mapping object and performs // allocation from it. The allocator takes ownership of the mapping object. class BASE_EXPORT WritableSharedPersistentMemoryAllocator : public PersistentMemoryAllocator { … }; // This allocator takes a read-only shared memory mapping object and performs // allocation from it. The allocator takes ownership of the mapping object. class BASE_EXPORT ReadOnlySharedPersistentMemoryAllocator : public PersistentMemoryAllocator { … }; // NACL doesn't support any kind of file access in build. #if !BUILDFLAG(IS_NACL) // This allocator takes a memory-mapped file object and performs allocation // from it. The allocator takes ownership of the file object. class BASE_EXPORT FilePersistentMemoryAllocator : public PersistentMemoryAllocator { … }; #endif // !BUILDFLAG(IS_NACL) // An allocation that is defined but not executed until required at a later // time. This allows for potential users of an allocation to be decoupled // from the logic that defines it. In addition, there can be multiple users // of the same allocation or any region thereof that are guaranteed to always // use the same space. It's okay to copy/move these objects. // // This is a top-level class instead of an inner class of the PMA so that it // can be forward-declared in other header files without the need to include // the full contents of this file. class BASE_EXPORT DelayedPersistentAllocation { … }; } // namespace base #endif // BASE_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_