| Index: services/blamer/shared_memory_heap.h
|
| diff --git a/services/blamer/shared_memory_heap.h b/services/blamer/shared_memory_heap.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e38142cf104c0b8fd29eaf301fea8146c02a340b
|
| --- /dev/null
|
| +++ b/services/blamer/shared_memory_heap.h
|
| @@ -0,0 +1,155 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Defines a shared memory heap. One of these is created by each process
|
| +// using the blame service. This heap takes care of registering all of its slabs
|
| +// with the central blamer service, allowing it to iterate over all blame
|
| +// information across all processes.
|
| +
|
| +#ifndef SERVICES_BLAMER_SHARED_MEMORY_HEAP_H_
|
| +#define SERVICES_BLAMER_SHARED_MEMORY_HEAP_H_
|
| +
|
| +#include "base/metrics/persistent_memory_allocator.h"
|
| +#include "mojo/public/cpp/system/buffer.h"
|
| +#include "services/blamer/heap_object_types.h"
|
| +#include "services/blamer/public/interfaces/shared_memory_heap_registry.mojom.h"
|
| +
|
| +namespace blamer {
|
| +
|
| +// This class is thread safe. Most of the operations will actually be performed
|
| +// without using any locks, however occasionally a lock will need to be
|
| +// acquired in support of some operations.
|
| +class SharedMemoryHeap {
|
| + public:
|
| + static constexpr size_t kSlabSizeBits = 22;
|
| + static constexpr size_t kSlabSize = 1 << kSlabSizeBits;
|
| +
|
| + // Represents a pointer in a process-portable way. This is what would be sent
|
| + // over IPC to communicate pointers between processes. Knowing the ID of the
|
| + // process owning the memory and the |raw_value| of the PortablePointer is
|
| + // sufficient to extract an actual pointer to the object in the process
|
| + // hosting the service.
|
| + struct PortablePointer {
|
| + union {
|
| + uint32_t raw_value;
|
| + struct {
|
| + unsigned int slab_id : 32 - kSlabSizeBits;
|
| + unsigned int slab_offset : kSlabSizeBits;
|
| + };
|
| + };
|
| + };
|
| + static_assert(sizeof(PortablePointer) == 4,
|
| + "unexpected PortablePointer size");
|
| +
|
| + // Encapsulates pointers as they are doled out by this shared memory
|
| + // allocator. Dereferencing has a non-trivial cost so the result should
|
| + // ideally be cached by clients that need to do this often.
|
| + template<typename ObjectType>
|
| + struct TypedLocalPointer {
|
| + TypedLocalPointer(void* slab, PortablePointer pointer)
|
| + : slab(slab), pointer(pointer) {
|
| + }
|
| +
|
| + ObjectType* Get() const {
|
| + auto* allocator = reinterpret_cast<base::PersistentMemoryAllocator*>(
|
| + slab);
|
| + base::PersistentMemoryAllocator::Reference ref = pointer.slab_offset;
|
| + return allocator->GetAsObject<ObjectType>(ref);
|
| + }
|
| + ObjectType* operator->() const { return Get(); }
|
| + ObjectType& operator*() const { return *Get(); }
|
| +
|
| + void* slab;
|
| + PortablePointer pointer;
|
| + };
|
| +
|
| + SharedMemoryHeap(mojom::SharedMemoryHeapRegistryPtr heap_registry);
|
| + ~SharedMemoryHeap();
|
| +
|
| + // Allocates an object on the shared memory heap. Uses the actual object size.
|
| + template<typename ObjectType>
|
| + TypedLocalPointer<ObjectType> Allocate() {
|
| + return MakePointer<ObjectType>(Allocate(
|
| + ObjectType::kPersistentTypeId, sizeof(ObjectType)));
|
| + }
|
| +
|
| + // Allocates an object on the shared memory heap. Uses the request object
|
| + // size.
|
| + template<typename ObjectType>
|
| + TypedLocalPointer<ObjectType> Allocate(size_t object_size) {
|
| + return MakePointer<ObjectType>(Allocate(
|
| + ObjectType::kPersistentTypeId, object_size));
|
| + }
|
| +
|
| + // Frees an object. Once freed the object will no longer be visible to
|
| + // remote processes.
|
| + template<typename ObjectType>
|
| + void Free(const TypedLocalPointer<ObjectType>& pointer) {
|
| + Free(ObjectType::kPersistentTypeId, MakePointer(pointer));
|
| + }
|
| +
|
| + private:
|
| + struct LocalPointer {
|
| + void* slab;
|
| + PortablePointer pointer;
|
| + };
|
| +
|
| + struct Slab {
|
| + Slab();
|
| + Slab(Slab&& other);
|
| + ~Slab();
|
| +
|
| + mojo::ScopedSharedBufferHandle buffer;
|
| + mojo::ScopedSharedBufferMapping mapping;
|
| + std::unique_ptr<base::PersistentMemoryAllocator> allocator;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(Slab);
|
| + };
|
| +
|
| + // Returns the current slab, creating one if none exists.
|
| + base::PersistentMemoryAllocator* GetCurrentSlab();
|
| +
|
| + // Creates a new slab, and updates |current_slab_|. Returns a pointer to the
|
| + // newly created slab.
|
| + base::PersistentMemoryAllocator* CreateNewSlab(
|
| + base::PersistentMemoryAllocator* current_slab);
|
| +
|
| + // Creates a TypedLocalPointer from an untyped LocalPointer.
|
| + template<typename ObjectType>
|
| + TypedLocalPointer<ObjectType> MakePointer(const LocalPointer& pointer) {
|
| + return TypedLocalPointer<ObjectType>(pointer.slab, pointer.pointer);
|
| + }
|
| +
|
| + // Creates an untyped LocalPointer from a TypedLocalPointer.
|
| + template<typename ObjectType>
|
| + LocalPointer MakePointer(const TypedLocalPointer<ObjectType>& pointer) {
|
| + LocalPointer lp = {};
|
| + lp.slab = pointer.slab;
|
| + lp.slab = pointer.pointer = pointer.pointer;
|
| + return lp;
|
| + }
|
| +
|
| + // Allocates an object from the current slab. Creates a new slab if the
|
| + // current slab fails to perform the allocation.
|
| + LocalPointer Allocate(HeapObjectType object_type, size_t object_size);
|
| +
|
| + // Frees the provided object.
|
| + void Free(HeapObjectType object_type, const LocalPointer& pointer);
|
| +
|
| + // Pointer to the heap registry to be notified of new slabs.
|
| + mojom::SharedMemoryHeapRegistryPtr heap_registry_;
|
| +
|
| + // The current persistent memory allocator. This is updated in a lock-free
|
| + // manner. The common use case is to grab the current allocator and make an
|
| + // allocation, which is very fast.
|
| + std::atomic<base::PersistentMemoryAllocator*> current_slab_;
|
| +
|
| + // |current_slab_| is used as a lock for modifying this safely.
|
| + std::vector<Slab> slabs_;
|
| +};
|
| +
|
| +} // namespace blamer
|
| +
|
| +#endif // SERVICES_BLAMER_SHARED_MEMORY_HEAP_H_
|
|
|