1 // Copyright 2014 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.
5 #include "base/basictypes.h"
6 #include "base/memory/discardable_shared_memory.h"
7 #include "base/process/process_metrics.h"
8 #include "testing/gtest/include/gtest/gtest.h"
13 class TestDiscardableSharedMemory
: public DiscardableSharedMemory
{
15 TestDiscardableSharedMemory() {}
17 explicit TestDiscardableSharedMemory(SharedMemoryHandle handle
)
18 : DiscardableSharedMemory(handle
) {}
20 void SetNow(Time now
) { now_
= now
; }
23 // Overriden from DiscardableSharedMemory:
24 Time
Now() const override
{ return now_
; }
29 TEST(DiscardableSharedMemoryTest
, CreateAndMap
) {
30 const uint32 kDataSize
= 1024;
32 TestDiscardableSharedMemory memory
;
33 bool rv
= memory
.CreateAndMap(kDataSize
);
35 EXPECT_GE(memory
.mapped_size(), kDataSize
);
38 TEST(DiscardableSharedMemoryTest
, CreateFromHandle
) {
39 const uint32 kDataSize
= 1024;
41 TestDiscardableSharedMemory memory1
;
42 bool rv
= memory1
.CreateAndMap(kDataSize
);
45 SharedMemoryHandle shared_handle
;
47 memory1
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
48 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle
));
50 TestDiscardableSharedMemory
memory2(shared_handle
);
51 rv
= memory2
.Map(kDataSize
);
55 TEST(DiscardableSharedMemoryTest
, LockAndUnlock
) {
56 const uint32 kDataSize
= 1024;
58 TestDiscardableSharedMemory memory1
;
59 bool rv
= memory1
.CreateAndMap(kDataSize
);
62 // Memory is initially locked. Unlock it.
63 memory1
.SetNow(Time::FromDoubleT(1));
66 // Lock and unlock memory.
67 auto lock_rv
= memory1
.Lock(0, 0);
68 EXPECT_EQ(DiscardableSharedMemory::SUCCESS
, lock_rv
);
69 memory1
.SetNow(Time::FromDoubleT(2));
72 // Lock again before duplicating and passing ownership to new instance.
73 lock_rv
= memory1
.Lock(0, 0);
74 EXPECT_EQ(DiscardableSharedMemory::SUCCESS
, lock_rv
);
76 SharedMemoryHandle shared_handle
;
78 memory1
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
79 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle
));
81 TestDiscardableSharedMemory
memory2(shared_handle
);
82 rv
= memory2
.Map(kDataSize
);
85 // Unlock second instance.
86 memory2
.SetNow(Time::FromDoubleT(3));
89 // Lock second instance before passing ownership back to first instance.
90 lock_rv
= memory2
.Lock(0, 0);
91 EXPECT_EQ(DiscardableSharedMemory::SUCCESS
, lock_rv
);
93 // Memory should still be resident.
94 rv
= memory1
.IsMemoryResident();
97 // Unlock first instance.
98 memory1
.SetNow(Time::FromDoubleT(4));
102 TEST(DiscardableSharedMemoryTest
, Purge
) {
103 const uint32 kDataSize
= 1024;
105 TestDiscardableSharedMemory memory1
;
106 bool rv
= memory1
.CreateAndMap(kDataSize
);
109 SharedMemoryHandle shared_handle
;
111 memory1
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
112 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle
));
114 TestDiscardableSharedMemory
memory2(shared_handle
);
115 rv
= memory2
.Map(kDataSize
);
118 // This should fail as memory is locked.
119 rv
= memory1
.Purge(Time::FromDoubleT(1));
122 memory2
.SetNow(Time::FromDoubleT(2));
123 memory2
.Unlock(0, 0);
125 ASSERT_TRUE(memory2
.IsMemoryResident());
127 // Memory is unlocked, but our usage timestamp is incorrect.
128 rv
= memory1
.Purge(Time::FromDoubleT(3));
131 ASSERT_TRUE(memory2
.IsMemoryResident());
133 // Memory is unlocked and our usage timestamp should be correct.
134 rv
= memory1
.Purge(Time::FromDoubleT(4));
137 // Lock should fail as memory has been purged.
138 auto lock_rv
= memory2
.Lock(0, 0);
139 EXPECT_EQ(DiscardableSharedMemory::FAILED
, lock_rv
);
141 ASSERT_FALSE(memory2
.IsMemoryResident());
144 TEST(DiscardableSharedMemoryTest
, LastUsed
) {
145 const uint32 kDataSize
= 1024;
147 TestDiscardableSharedMemory memory1
;
148 bool rv
= memory1
.CreateAndMap(kDataSize
);
151 SharedMemoryHandle shared_handle
;
153 memory1
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
154 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle
));
156 TestDiscardableSharedMemory
memory2(shared_handle
);
157 rv
= memory2
.Map(kDataSize
);
160 memory2
.SetNow(Time::FromDoubleT(1));
161 memory2
.Unlock(0, 0);
163 EXPECT_EQ(memory2
.last_known_usage(), Time::FromDoubleT(1));
165 auto lock_rv
= memory2
.Lock(0, 0);
166 EXPECT_EQ(DiscardableSharedMemory::SUCCESS
, lock_rv
);
168 // This should fail as memory is locked.
169 rv
= memory1
.Purge(Time::FromDoubleT(2));
172 // Last usage should have been updated to timestamp passed to Purge above.
173 EXPECT_EQ(memory1
.last_known_usage(), Time::FromDoubleT(2));
175 memory2
.SetNow(Time::FromDoubleT(3));
176 memory2
.Unlock(0, 0);
178 // Usage time should be correct for |memory2| instance.
179 EXPECT_EQ(memory2
.last_known_usage(), Time::FromDoubleT(3));
181 // However, usage time has not changed as far as |memory1| instance knows.
182 EXPECT_EQ(memory1
.last_known_usage(), Time::FromDoubleT(2));
184 // Memory is unlocked, but our usage timestamp is incorrect.
185 rv
= memory1
.Purge(Time::FromDoubleT(4));
188 // The failed purge attempt should have updated usage time to the correct
190 EXPECT_EQ(memory1
.last_known_usage(), Time::FromDoubleT(3));
192 // Purge memory through |memory2| instance. The last usage time should be
193 // set to 0 as a result of this.
194 rv
= memory2
.Purge(Time::FromDoubleT(5));
196 EXPECT_TRUE(memory2
.last_known_usage().is_null());
198 // This should fail as memory has already been purged and |memory1|'s usage
199 // time is incorrect as a result.
200 rv
= memory1
.Purge(Time::FromDoubleT(6));
203 // The failed purge attempt should have updated usage time to the correct
205 EXPECT_TRUE(memory1
.last_known_usage().is_null());
207 // Purge should succeed now that usage time is correct.
208 rv
= memory1
.Purge(Time::FromDoubleT(7));
212 TEST(DiscardableSharedMemoryTest
, LockShouldAlwaysFailAfterSuccessfulPurge
) {
213 const uint32 kDataSize
= 1024;
215 TestDiscardableSharedMemory memory1
;
216 bool rv
= memory1
.CreateAndMap(kDataSize
);
219 SharedMemoryHandle shared_handle
;
221 memory1
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
222 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle
));
224 TestDiscardableSharedMemory
memory2(shared_handle
);
225 rv
= memory2
.Map(kDataSize
);
228 memory2
.SetNow(Time::FromDoubleT(1));
229 memory2
.Unlock(0, 0);
231 rv
= memory2
.Purge(Time::FromDoubleT(2));
234 // Lock should fail as memory has been purged.
235 auto lock_rv
= memory2
.Lock(0, 0);
236 EXPECT_EQ(DiscardableSharedMemory::FAILED
, lock_rv
);
239 TEST(DiscardableSharedMemoryTest
, LockAndUnlockRange
) {
240 const uint32 kDataSize
= 32;
242 uint32 data_size_in_bytes
= kDataSize
* base::GetPageSize();
244 TestDiscardableSharedMemory memory1
;
245 bool rv
= memory1
.CreateAndMap(data_size_in_bytes
);
248 SharedMemoryHandle shared_handle
;
250 memory1
.ShareToProcess(GetCurrentProcessHandle(), &shared_handle
));
251 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle
));
253 TestDiscardableSharedMemory
memory2(shared_handle
);
254 rv
= memory2
.Map(data_size_in_bytes
);
257 // Unlock first page.
258 memory2
.SetNow(Time::FromDoubleT(1));
259 memory2
.Unlock(0, base::GetPageSize());
261 rv
= memory1
.Purge(Time::FromDoubleT(2));
264 // Lock first page again.
265 memory2
.SetNow(Time::FromDoubleT(3));
266 auto lock_rv
= memory2
.Lock(0, base::GetPageSize());
267 EXPECT_NE(DiscardableSharedMemory::FAILED
, lock_rv
);
269 // Unlock first page.
270 memory2
.SetNow(Time::FromDoubleT(4));
271 memory2
.Unlock(0, base::GetPageSize());
273 rv
= memory1
.Purge(Time::FromDoubleT(5));
276 // Unlock second page.
277 memory2
.SetNow(Time::FromDoubleT(6));
278 memory2
.Unlock(base::GetPageSize(), base::GetPageSize());
280 rv
= memory1
.Purge(Time::FromDoubleT(7));
283 // Unlock anything onwards.
284 memory2
.SetNow(Time::FromDoubleT(8));
285 memory2
.Unlock(2 * base::GetPageSize(), 0);
287 // Memory is unlocked, but our usage timestamp is incorrect.
288 rv
= memory1
.Purge(Time::FromDoubleT(9));
291 // The failed purge attempt should have updated usage time to the correct
293 EXPECT_EQ(Time::FromDoubleT(8), memory1
.last_known_usage());
295 // Purge should now succeed.
296 rv
= memory1
.Purge(Time::FromDoubleT(10));
300 TEST(DiscardableSharedMemoryTest
, MappedSize
) {
301 const uint32 kDataSize
= 1024;
303 TestDiscardableSharedMemory memory
;
304 bool rv
= memory
.CreateAndMap(kDataSize
);
307 EXPECT_LE(kDataSize
, memory
.mapped_size());
309 // Mapped size should be 0 after memory segment has been unmapped.
312 EXPECT_EQ(0u, memory
.mapped_size());
315 TEST(DiscardableSharedMemoryTest
, Close
) {
316 const uint32 kDataSize
= 1024;
318 TestDiscardableSharedMemory memory
;
319 bool rv
= memory
.CreateAndMap(kDataSize
);
322 // Mapped size should be unchanged after memory segment has been closed.
324 EXPECT_LE(kDataSize
, memory
.mapped_size());
326 // Memory is initially locked. Unlock it.
327 memory
.SetNow(Time::FromDoubleT(1));
330 // Lock and unlock memory.
331 auto lock_rv
= memory
.Lock(0, 0);
332 EXPECT_EQ(DiscardableSharedMemory::SUCCESS
, lock_rv
);
333 memory
.SetNow(Time::FromDoubleT(2));
337 #if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
338 TEST(DiscardableSharedMemoryTest
, Shrink
) {
339 const uint32 kDataSize
= 1024;
341 TestDiscardableSharedMemory memory
;
342 bool rv
= memory
.CreateAndMap(kDataSize
);
345 EXPECT_NE(0u, memory
.mapped_size());
347 // Mapped size should be 0 after shrinking memory segment.
349 EXPECT_EQ(0u, memory
.mapped_size());