Index: base/metrics/persistent_memory_allocator.h |
diff --git a/base/metrics/persistent_memory_allocator.h b/base/metrics/persistent_memory_allocator.h |
index 94a7744bfb2714d74ae956b41e1ceff7483176e2..b931b2f6b61add814a5a1ad3c4436fd3280758d1 100644 |
--- a/base/metrics/persistent_memory_allocator.h |
+++ b/base/metrics/persistent_memory_allocator.h |
@@ -767,6 +767,102 @@ class BASE_EXPORT FilePersistentMemoryAllocator |
}; |
#endif // !defined(OS_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 { |
+ public: |
+ using Reference = PersistentMemoryAllocator::Reference; |
+ |
+ // Creates a delayed allocation using the specified |allocator|. When |
+ // needed, the memory will be allocated using the specified |type| and |
+ // |size|. If |offset| is given, the returned pointer will be at that |
+ // offset into the segment; this allows combining allocations into a |
+ // single persistent segment to reduce overhead and means an "all or |
+ // nothing" request. Note that |size| is always the total memory size |
+ // and |offset| is just indicating the start of a block within it. If |
+ // |make_iterable| was true, the allocation will made iterable when it |
+ // is created; already existing allocations are not changed. |
+ // |
+ // Once allocated, a reference to the segment will be stored at |ref|. |
+ // This shared location must be initialized to zero (0); it is checked |
+ // with every Get() request to see if the allocation has already been |
+ // done. |
+ // |
+ // For convenience, methods taking both Atomic32 and std::atomic<Reference> |
+ // are defined. |
+ DelayedPersistentAllocation(PersistentMemoryAllocator* allocator, |
+ subtle::Atomic32* ref, |
+ uint32_t type, |
+ size_t size, |
+ bool make_iterable); |
+ DelayedPersistentAllocation(PersistentMemoryAllocator* allocator, |
+ subtle::Atomic32* ref, |
+ uint32_t type, |
+ size_t size, |
+ size_t offset, |
+ bool make_iterable); |
+ DelayedPersistentAllocation(PersistentMemoryAllocator* allocator, |
+ std::atomic<Reference>* ref, |
+ uint32_t type, |
+ size_t size, |
+ bool make_iterable); |
+ DelayedPersistentAllocation(PersistentMemoryAllocator* allocator, |
+ std::atomic<Reference>* ref, |
+ uint32_t type, |
+ size_t size, |
+ size_t offset, |
+ bool make_iterable); |
+ ~DelayedPersistentAllocation(); |
+ |
+ // Gets a pointer to the defined allocation. This will realize the request |
+ // and update the reference provided during construction. The memory will |
+ // be zeroed the first time it is returned, after that it is shared with |
+ // all other Get() requests and so shows any changes made to it elsewhere. |
+ // |
+ // If the allocation fails for any reason, null will be returned. This works |
+ // even on "const" objects because the allocation is already defined, just |
+ // delayed. |
+ void* Get() const; |
+ |
+ // Gets the internal reference value. If this returns a non-zero value then |
+ // a subsequent call to Get() will do nothing but convert that reference into |
+ // a memory location -- useful for accessing an existing allocation without |
+ // creating one unnecessarily. |
+ Reference reference() const { |
+ return reference_->load(std::memory_order_relaxed); |
+ } |
+ |
+ private: |
+ // The underlying object that does the actual allocation of memory. Its |
+ // lifetime must exceed that of all DelayedPersistentAllocation objects |
+ // that use it. |
+ PersistentMemoryAllocator* const allocator_; |
+ |
+ // The desired type and size of the allocated segment plus the offset |
+ // within it for the defined request. |
+ const uint32_t type_; |
+ const size_t size_; |
+ const size_t offset_; |
+ |
+ // Flag indicating if allocation should be made iterable when done. |
+ const bool make_iterable_; |
+ |
+ // The location at which a reference to the allocated segment is to be |
+ // stored once the allocation is complete. If multiple delayed allocations |
+ // share the same pointer then an allocation on one will amount to an |
+ // allocation for all. |
+ volatile std::atomic<Reference>* const reference_; |
+ |
+ // No DISALLOW_COPY_AND_ASSIGN as it's okay to copy/move these objects. |
+}; |
+ |
} // namespace base |
#endif // BASE_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_ |