| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "mojo/services/html_viewer/discardable_memory_allocator.h" | 
|  | 6 | 
|  | 7 #include "base/memory/discardable_memory.h" | 
|  | 8 #include "base/memory/weak_ptr.h" | 
|  | 9 #include "base/stl_util.h" | 
|  | 10 | 
|  | 11 namespace html_viewer { | 
|  | 12 | 
|  | 13 // Represents an actual memory chunk. This is an object owned by | 
|  | 14 // DiscardableMemoryAllocator. DiscardableMemoryChunkImpl are passed to the | 
|  | 15 // rest of the program, and access this memory through a weak ptr. | 
|  | 16 class DiscardableMemoryAllocator::OwnedMemoryChunk { | 
|  | 17  public: | 
|  | 18   OwnedMemoryChunk(size_t size, DiscardableMemoryAllocator* allocator) | 
|  | 19       : is_locked_(true), | 
|  | 20         size_(size), | 
|  | 21         memory_(new uint8_t[size]), | 
|  | 22         allocator_(allocator), | 
|  | 23         weak_factory_(this) {} | 
|  | 24   ~OwnedMemoryChunk() {} | 
|  | 25 | 
|  | 26   void Lock() { | 
|  | 27     DCHECK(!is_locked_); | 
|  | 28     is_locked_ = true; | 
|  | 29     allocator_->NotifyLocked(unlocked_position_); | 
|  | 30   } | 
|  | 31 | 
|  | 32   void Unlock() { | 
|  | 33     DCHECK(is_locked_); | 
|  | 34     is_locked_ = false; | 
|  | 35     unlocked_position_ = allocator_->NotifyUnlocked(this); | 
|  | 36   } | 
|  | 37 | 
|  | 38   bool is_locked() const { return is_locked_; } | 
|  | 39   size_t size() const { return size_; } | 
|  | 40   void* Memory() const { | 
|  | 41     DCHECK(is_locked_); | 
|  | 42     return memory_.get(); | 
|  | 43   } | 
|  | 44 | 
|  | 45   base::WeakPtr<OwnedMemoryChunk> GetWeakPtr() { | 
|  | 46     return weak_factory_.GetWeakPtr(); | 
|  | 47   } | 
|  | 48 | 
|  | 49  private: | 
|  | 50   bool is_locked_; | 
|  | 51   size_t size_; | 
|  | 52   scoped_ptr<uint8_t[]> memory_; | 
|  | 53   DiscardableMemoryAllocator* allocator_; | 
|  | 54 | 
|  | 55   std::list<OwnedMemoryChunk*>::iterator unlocked_position_; | 
|  | 56 | 
|  | 57   base::WeakPtrFactory<OwnedMemoryChunk> weak_factory_; | 
|  | 58 | 
|  | 59   DISALLOW_IMPLICIT_CONSTRUCTORS(OwnedMemoryChunk); | 
|  | 60 }; | 
|  | 61 | 
|  | 62 namespace { | 
|  | 63 | 
|  | 64 // Interface to the rest of the program. These objects are owned outside of the | 
|  | 65 // allocator and wrap a weak ptr. | 
|  | 66 class DiscardableMemoryChunkImpl : public base::DiscardableMemory { | 
|  | 67  public: | 
|  | 68   explicit DiscardableMemoryChunkImpl( | 
|  | 69       base::WeakPtr<DiscardableMemoryAllocator::OwnedMemoryChunk> chunk) | 
|  | 70       : memory_chunk_(chunk) {} | 
|  | 71   ~DiscardableMemoryChunkImpl() override { | 
|  | 72     // Either the memory chunk is invalid (because the backing has gone away), | 
|  | 73     // or the memory chunk is unlocked (because leaving the chunk locked once | 
|  | 74     // we deallocate means the chunk will never get cleaned up). | 
|  | 75     DCHECK(!memory_chunk_ || !memory_chunk_->is_locked()); | 
|  | 76   } | 
|  | 77 | 
|  | 78   // Overridden from DiscardableMemoryChunk: | 
|  | 79   bool Lock() override { | 
|  | 80     if (!memory_chunk_) | 
|  | 81       return false; | 
|  | 82 | 
|  | 83     memory_chunk_->Lock(); | 
|  | 84     return true; | 
|  | 85   } | 
|  | 86 | 
|  | 87   void Unlock() override { | 
|  | 88     DCHECK(memory_chunk_); | 
|  | 89     memory_chunk_->Unlock(); | 
|  | 90   } | 
|  | 91 | 
|  | 92   void* Memory() const override { | 
|  | 93     if (memory_chunk_) | 
|  | 94       return memory_chunk_->Memory(); | 
|  | 95     return nullptr; | 
|  | 96   } | 
|  | 97 | 
|  | 98  private: | 
|  | 99   base::WeakPtr<DiscardableMemoryAllocator::OwnedMemoryChunk> memory_chunk_; | 
|  | 100 | 
|  | 101   DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl); | 
|  | 102 }; | 
|  | 103 | 
|  | 104 }  // namespace | 
|  | 105 | 
|  | 106 DiscardableMemoryAllocator::DiscardableMemoryAllocator( | 
|  | 107     size_t desired_max_memory) | 
|  | 108     : desired_max_memory_(desired_max_memory), | 
|  | 109       total_live_memory_(0u), | 
|  | 110       locked_chunks_(0) { | 
|  | 111 } | 
|  | 112 | 
|  | 113 DiscardableMemoryAllocator::~DiscardableMemoryAllocator() { | 
|  | 114   DCHECK_EQ(0, locked_chunks_); | 
|  | 115   STLDeleteElements(&live_unlocked_chunks_); | 
|  | 116 } | 
|  | 117 | 
|  | 118 scoped_ptr<base::DiscardableMemory> | 
|  | 119 DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) { | 
|  | 120   OwnedMemoryChunk* chunk = new OwnedMemoryChunk(size, this); | 
|  | 121   total_live_memory_ += size; | 
|  | 122   locked_chunks_++; | 
|  | 123 | 
|  | 124   // Go through the list of unlocked live chunks starting from the least | 
|  | 125   // recently used, freeing as many as we can until we get our size under the | 
|  | 126   // desired maximum. | 
|  | 127   auto it = live_unlocked_chunks_.begin(); | 
|  | 128   while (total_live_memory_ > desired_max_memory_ && | 
|  | 129          it != live_unlocked_chunks_.end()) { | 
|  | 130     total_live_memory_ -= (*it)->size(); | 
|  | 131     delete *it; | 
|  | 132     it = live_unlocked_chunks_.erase(it); | 
|  | 133   } | 
|  | 134 | 
|  | 135   return make_scoped_ptr(new DiscardableMemoryChunkImpl(chunk->GetWeakPtr())); | 
|  | 136 } | 
|  | 137 | 
|  | 138 std::list<DiscardableMemoryAllocator::OwnedMemoryChunk*>::iterator | 
|  | 139 DiscardableMemoryAllocator::NotifyUnlocked( | 
|  | 140     DiscardableMemoryAllocator::OwnedMemoryChunk* chunk) { | 
|  | 141   locked_chunks_--; | 
|  | 142   return live_unlocked_chunks_.insert(live_unlocked_chunks_.end(), chunk); | 
|  | 143 } | 
|  | 144 | 
|  | 145 void DiscardableMemoryAllocator::NotifyLocked( | 
|  | 146     std::list<OwnedMemoryChunk*>::iterator it) { | 
|  | 147   locked_chunks_++; | 
|  | 148   live_unlocked_chunks_.erase(it); | 
|  | 149 } | 
|  | 150 | 
|  | 151 }  // namespace html_viewer | 
| OLD | NEW | 
|---|