Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Side by Side Diff: base/memory/discardable_memory_android.cc

Issue 15650016: [Not for review] Discardable memory emulation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/memory/discardable_memory.h" 5 #include "base/memory/discardable_memory.h"
6 6
7 #include <sys/mman.h> 7 #include <sys/mman.h>
8 #include <unistd.h> 8 #include <unistd.h>
9 9
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/posix/eintr_wrapper.h" 12 #include "base/posix/eintr_wrapper.h"
13 #include "base/synchronization/lock.h" 13 #include "base/synchronization/lock.h"
14 #include "third_party/ashmem/ashmem.h" 14 #include "third_party/ashmem/ashmem.h"
15 15
16 namespace base {
17
16 namespace { 18 namespace {
17 19
18 base::LazyInstance<base::Lock>::Leaky g_discardable_memory_lock = 20 base::LazyInstance<base::Lock>::Leaky g_discardable_memory_lock =
19 LAZY_INSTANCE_INITIALIZER; 21 LAZY_INSTANCE_INITIALIZER;
20 22
21 // Total number of discardable memory in the process. 23 // Total number of discardable memory in the process.
22 int g_num_discardable_memory = 0; 24 int g_num_discardable_memory = 0;
23 25
24 // Upper limit on the number of discardable memory to avoid hitting file 26 // Upper limit on the number of discardable memory to avoid hitting file
25 // descriptor limit. 27 // descriptor limit.
26 const int kDiscardableMemoryNumLimit = 128; 28 const int kDiscardableMemoryNumLimit = 128;
27 29
28 } 30 class DiscardableMemoryAndroid : public DiscardableMemory {
31 public:
32 DiscardableMemoryAndroid()
33 : memory_(NULL),
34 size_(0),
35 is_locked_(false),
36 fd_(-1) {
37 }
29 38
30 namespace base { 39 virtual ~DiscardableMemoryAndroid() {
40 if (is_locked_)
41 Unlock();
42 // If fd_ is smaller than 0, initialization must have failed and
43 // g_num_discardable_memory is not incremented by the caller.
44 if (fd_ < 0)
45 return;
46 HANDLE_EINTR(close(fd_));
47 fd_ = -1;
48 ReleaseFileDescriptor();
49 }
31 50
32 // static 51 virtual bool InitializeAndLock(size_t size) OVERRIDE {
33 bool DiscardableMemory::Supported() { 52 // When this function returns true, fd_ should be larger or equal than 0
34 return true; 53 // and g_num_discardable_memory is incremented by 1. Otherwise, fd_
35 } 54 // is less than 0 and g_num_discardable_memory is not incremented by
55 // the caller.
56 DCHECK_EQ(fd_, -1);
57 DCHECK(!memory_);
58 if (!ReserveFileDescriptor())
59 return false;
36 60
37 DiscardableMemory::~DiscardableMemory() { 61 size_ = size;
38 if (is_locked_) 62 fd_ = ashmem_create_region("", size);
39 Unlock();
40 // If fd_ is smaller than 0, initialization must have failed and
41 // g_num_discardable_memory is not incremented by the caller.
42 if (fd_ < 0)
43 return;
44 HANDLE_EINTR(close(fd_));
45 fd_ = -1;
46 ReleaseFileDescriptor();
47 }
48 63
49 bool DiscardableMemory::ReserveFileDescriptor() { 64 if (fd_ < 0) {
50 base::AutoLock lock(g_discardable_memory_lock.Get()); 65 DLOG(ERROR) << "ashmem_create_region() failed";
51 if (g_num_discardable_memory < kDiscardableMemoryNumLimit) { 66 ReleaseFileDescriptor();
52 ++g_num_discardable_memory; 67 return false;
68 }
69
70 int err = ashmem_set_prot_region(fd_, PROT_READ | PROT_WRITE);
71 if (err < 0) {
72 DLOG(ERROR) << "Error " << err << " when setting protection of ashmem";
73 HANDLE_EINTR(close(fd_));
74 fd_ = -1;
75 ReleaseFileDescriptor();
76 return false;
77 }
78
79 if (!Map()) {
80 // Close the file descriptor in case of any initialization errors.
81 HANDLE_EINTR(close(fd_));
82 fd_ = -1;
83 ReleaseFileDescriptor();
84 return false;
85 }
86
87 is_locked_ = true;
53 return true; 88 return true;
54 } 89 }
55 return false;
56 }
57 90
58 void DiscardableMemory::ReleaseFileDescriptor() { 91 virtual LockDiscardableMemoryStatus Lock() OVERRIDE {
59 base::AutoLock lock(g_discardable_memory_lock.Get()); 92 DCHECK_NE(fd_, -1);
60 --g_num_discardable_memory; 93 DCHECK(!is_locked_);
61 DCHECK_LE(0, g_num_discardable_memory);
62 }
63 94
64 bool DiscardableMemory::InitializeAndLock(size_t size) { 95 bool purged = false;
65 // When this function returns true, fd_ should be larger or equal than 0 96 if (ashmem_pin_region(fd_, 0, 0) == ASHMEM_WAS_PURGED)
66 // and g_num_discardable_memory is incremented by 1. Otherwise, fd_ 97 purged = true;
67 // is less than 0 and g_num_discardable_memory is not incremented by
68 // the caller.
69 DCHECK_EQ(fd_, -1);
70 DCHECK(!memory_);
71 if (!ReserveFileDescriptor())
72 return false;
73 98
74 size_ = size; 99 if (!Map())
75 fd_ = ashmem_create_region("", size); 100 return DISCARDABLE_MEMORY_FAILED;
76 101
77 if (fd_ < 0) { 102 is_locked_ = true;
78 DLOG(ERROR) << "ashmem_create_region() failed"; 103 return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS;
79 ReleaseFileDescriptor(); 104 }
105
106 virtual void Unlock() OVERRIDE {
107 DCHECK_GE(fd_, 0);
108 DCHECK(is_locked_);
109
110 Unmap();
111 if (ashmem_unpin_region(fd_, 0, 0))
112 DLOG(ERROR) << "Failed to unpin memory.";
113 is_locked_ = false;
114 }
115
116 virtual void* Memory() OVERRIDE {
117 return memory_;
118 }
119
120 bool ReserveFileDescriptor() {
121 base::AutoLock lock(g_discardable_memory_lock.Get());
122 if (g_num_discardable_memory < kDiscardableMemoryNumLimit) {
123 ++g_num_discardable_memory;
124 return true;
125 }
80 return false; 126 return false;
81 } 127 }
82 128
83 int err = ashmem_set_prot_region(fd_, PROT_READ | PROT_WRITE); 129 void ReleaseFileDescriptor() {
84 if (err < 0) { 130 base::AutoLock lock(g_discardable_memory_lock.Get());
85 DLOG(ERROR) << "Error " << err << " when setting protection of ashmem"; 131 --g_num_discardable_memory;
86 HANDLE_EINTR(close(fd_)); 132 DCHECK_LE(0, g_num_discardable_memory);
87 fd_ = -1; 133 }
88 ReleaseFileDescriptor(); 134
135 bool Map() {
136 DCHECK(!memory_);
137 // There is a problem using MAP_PRIVATE here. As we are constantly calling
138 // Lock() and Unlock(), data could get lost if they are not written to the
139 // underlying file when Unlock() gets called.
140 memory_ = mmap(NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
141 if (memory_ == (void*)-1) {
142 DPLOG(ERROR) << "Failed to map memory.";
143 memory_ = NULL;
144 if (ashmem_unpin_region(fd_, 0, 0))
145 DLOG(ERROR) << "Failed to unpin memory.";
146 return false;
147 }
148 return true;
149 }
150
151 void Unmap() {
152 DCHECK(memory_);
153
154 if (-1 == munmap(memory_, size_))
155 DPLOG(ERROR) << "Failed to unmap memory.";
156
157 memory_ = NULL;
158 }
159
160 private:
161 void* memory_;
162 size_t size_;
163 bool is_locked_;
164 int fd_;
165
166 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryAndroid);
167 };
168
169 class BASE_EXPORT DiscardableMemoryProviderAndroid
170 : public DiscardableMemoryProvider {
171 public:
172 virtual DiscardableMemory* CreateDiscardableMemory() OVERRIDE {
173 return new DiscardableMemoryAndroid;
174 }
175
176 virtual bool PurgeForTestingSupported() const OVERRIDE {
89 return false; 177 return false;
90 } 178 }
91 179
92 if (!Map()) { 180 virtual void PurgeForTesting() OVERRIDE {
93 // Close the file descriptor in case of any initialization errors. 181 NOTIMPLEMENTED();
94 HANDLE_EINTR(close(fd_));
95 fd_ = -1;
96 ReleaseFileDescriptor();
97 return false;
98 } 182 }
183 };
99 184
100 is_locked_ = true; 185 } // namespace
101 return true;
102 }
103
104 LockDiscardableMemoryStatus DiscardableMemory::Lock() {
105 DCHECK_NE(fd_, -1);
106 DCHECK(!is_locked_);
107
108 bool purged = false;
109 if (ashmem_pin_region(fd_, 0, 0) == ASHMEM_WAS_PURGED)
110 purged = true;
111
112 if (!Map())
113 return DISCARDABLE_MEMORY_FAILED;
114
115 is_locked_ = true;
116 return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS;
117 }
118
119 void DiscardableMemory::Unlock() {
120 DCHECK_GE(fd_, 0);
121 DCHECK(is_locked_);
122
123 Unmap();
124 if (ashmem_unpin_region(fd_, 0, 0))
125 DLOG(ERROR) << "Failed to unpin memory.";
126 is_locked_ = false;
127 }
128
129 bool DiscardableMemory::Map() {
130 DCHECK(!memory_);
131 // There is a problem using MAP_PRIVATE here. As we are constantly calling
132 // Lock() and Unlock(), data could get lost if they are not written to the
133 // underlying file when Unlock() gets called.
134 memory_ = mmap(NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
135 if (memory_ == (void*)-1) {
136 DPLOG(ERROR) << "Failed to map memory.";
137 memory_ = NULL;
138 if (ashmem_unpin_region(fd_, 0, 0))
139 DLOG(ERROR) << "Failed to unpin memory.";
140 return false;
141 }
142 return true;
143 }
144
145 void DiscardableMemory::Unmap() {
146 DCHECK(memory_);
147
148 if (-1 == munmap(memory_, size_))
149 DPLOG(ERROR) << "Failed to unmap memory.";
150
151 memory_ = NULL;
152 }
153 186
154 // static 187 // static
155 bool DiscardableMemory::PurgeForTestingSupported() { 188 DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() {
156 return false; 189 base::Singleton<DiscardableMemoryProviderAndroid>::GetInstance();
157 }
158
159 // static
160 void DiscardableMemory::PurgeForTesting() {
161 NOTIMPLEMENTED();
162 } 190 }
163 191
164 } // namespace base 192 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698