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