| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 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" | |
| 9 | |
| 10 namespace base { | |
| 11 namespace { | |
| 12 | |
| 13 class TestDiscardableSharedMemory : public DiscardableSharedMemory { | |
| 14 public: | |
| 15 TestDiscardableSharedMemory() {} | |
| 16 | |
| 17 explicit TestDiscardableSharedMemory(SharedMemoryHandle handle) | |
| 18 : DiscardableSharedMemory(handle) {} | |
| 19 | |
| 20 void SetNow(Time now) { now_ = now; } | |
| 21 | |
| 22 private: | |
| 23 // Overriden from DiscardableSharedMemory: | |
| 24 Time Now() const override { return now_; } | |
| 25 | |
| 26 Time now_; | |
| 27 }; | |
| 28 | |
| 29 TEST(DiscardableSharedMemoryTest, CreateAndMap) { | |
| 30 const uint32 kDataSize = 1024; | |
| 31 | |
| 32 TestDiscardableSharedMemory memory; | |
| 33 bool rv = memory.CreateAndMap(kDataSize); | |
| 34 ASSERT_TRUE(rv); | |
| 35 EXPECT_GE(memory.mapped_size(), kDataSize); | |
| 36 } | |
| 37 | |
| 38 TEST(DiscardableSharedMemoryTest, CreateFromHandle) { | |
| 39 const uint32 kDataSize = 1024; | |
| 40 | |
| 41 TestDiscardableSharedMemory memory1; | |
| 42 bool rv = memory1.CreateAndMap(kDataSize); | |
| 43 ASSERT_TRUE(rv); | |
| 44 | |
| 45 SharedMemoryHandle shared_handle; | |
| 46 ASSERT_TRUE( | |
| 47 memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); | |
| 48 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle)); | |
| 49 | |
| 50 TestDiscardableSharedMemory memory2(shared_handle); | |
| 51 rv = memory2.Map(kDataSize); | |
| 52 ASSERT_TRUE(rv); | |
| 53 } | |
| 54 | |
| 55 TEST(DiscardableSharedMemoryTest, LockAndUnlock) { | |
| 56 const uint32 kDataSize = 1024; | |
| 57 | |
| 58 TestDiscardableSharedMemory memory1; | |
| 59 bool rv = memory1.CreateAndMap(kDataSize); | |
| 60 ASSERT_TRUE(rv); | |
| 61 | |
| 62 // Memory is initially locked. Unlock it. | |
| 63 memory1.SetNow(Time::FromDoubleT(1)); | |
| 64 memory1.Unlock(0, 0); | |
| 65 | |
| 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)); | |
| 70 memory1.Unlock(0, 0); | |
| 71 | |
| 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); | |
| 75 | |
| 76 SharedMemoryHandle shared_handle; | |
| 77 ASSERT_TRUE( | |
| 78 memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); | |
| 79 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle)); | |
| 80 | |
| 81 TestDiscardableSharedMemory memory2(shared_handle); | |
| 82 rv = memory2.Map(kDataSize); | |
| 83 ASSERT_TRUE(rv); | |
| 84 | |
| 85 // Unlock second instance. | |
| 86 memory2.SetNow(Time::FromDoubleT(3)); | |
| 87 memory2.Unlock(0, 0); | |
| 88 | |
| 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); | |
| 92 | |
| 93 // Memory should still be resident. | |
| 94 rv = memory1.IsMemoryResident(); | |
| 95 EXPECT_TRUE(rv); | |
| 96 | |
| 97 // Unlock first instance. | |
| 98 memory1.SetNow(Time::FromDoubleT(4)); | |
| 99 memory1.Unlock(0, 0); | |
| 100 } | |
| 101 | |
| 102 TEST(DiscardableSharedMemoryTest, Purge) { | |
| 103 const uint32 kDataSize = 1024; | |
| 104 | |
| 105 TestDiscardableSharedMemory memory1; | |
| 106 bool rv = memory1.CreateAndMap(kDataSize); | |
| 107 ASSERT_TRUE(rv); | |
| 108 | |
| 109 SharedMemoryHandle shared_handle; | |
| 110 ASSERT_TRUE( | |
| 111 memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); | |
| 112 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle)); | |
| 113 | |
| 114 TestDiscardableSharedMemory memory2(shared_handle); | |
| 115 rv = memory2.Map(kDataSize); | |
| 116 ASSERT_TRUE(rv); | |
| 117 | |
| 118 // This should fail as memory is locked. | |
| 119 rv = memory1.Purge(Time::FromDoubleT(1)); | |
| 120 EXPECT_FALSE(rv); | |
| 121 | |
| 122 memory2.SetNow(Time::FromDoubleT(2)); | |
| 123 memory2.Unlock(0, 0); | |
| 124 | |
| 125 ASSERT_TRUE(memory2.IsMemoryResident()); | |
| 126 | |
| 127 // Memory is unlocked, but our usage timestamp is incorrect. | |
| 128 rv = memory1.Purge(Time::FromDoubleT(3)); | |
| 129 EXPECT_FALSE(rv); | |
| 130 | |
| 131 ASSERT_TRUE(memory2.IsMemoryResident()); | |
| 132 | |
| 133 // Memory is unlocked and our usage timestamp should be correct. | |
| 134 rv = memory1.Purge(Time::FromDoubleT(4)); | |
| 135 EXPECT_TRUE(rv); | |
| 136 | |
| 137 // Lock should fail as memory has been purged. | |
| 138 auto lock_rv = memory2.Lock(0, 0); | |
| 139 EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv); | |
| 140 | |
| 141 ASSERT_FALSE(memory2.IsMemoryResident()); | |
| 142 } | |
| 143 | |
| 144 TEST(DiscardableSharedMemoryTest, LastUsed) { | |
| 145 const uint32 kDataSize = 1024; | |
| 146 | |
| 147 TestDiscardableSharedMemory memory1; | |
| 148 bool rv = memory1.CreateAndMap(kDataSize); | |
| 149 ASSERT_TRUE(rv); | |
| 150 | |
| 151 SharedMemoryHandle shared_handle; | |
| 152 ASSERT_TRUE( | |
| 153 memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); | |
| 154 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle)); | |
| 155 | |
| 156 TestDiscardableSharedMemory memory2(shared_handle); | |
| 157 rv = memory2.Map(kDataSize); | |
| 158 ASSERT_TRUE(rv); | |
| 159 | |
| 160 memory2.SetNow(Time::FromDoubleT(1)); | |
| 161 memory2.Unlock(0, 0); | |
| 162 | |
| 163 EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1)); | |
| 164 | |
| 165 auto lock_rv = memory2.Lock(0, 0); | |
| 166 EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv); | |
| 167 | |
| 168 // This should fail as memory is locked. | |
| 169 rv = memory1.Purge(Time::FromDoubleT(2)); | |
| 170 ASSERT_FALSE(rv); | |
| 171 | |
| 172 // Last usage should have been updated to timestamp passed to Purge above. | |
| 173 EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2)); | |
| 174 | |
| 175 memory2.SetNow(Time::FromDoubleT(3)); | |
| 176 memory2.Unlock(0, 0); | |
| 177 | |
| 178 // Usage time should be correct for |memory2| instance. | |
| 179 EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(3)); | |
| 180 | |
| 181 // However, usage time has not changed as far as |memory1| instance knows. | |
| 182 EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2)); | |
| 183 | |
| 184 // Memory is unlocked, but our usage timestamp is incorrect. | |
| 185 rv = memory1.Purge(Time::FromDoubleT(4)); | |
| 186 EXPECT_FALSE(rv); | |
| 187 | |
| 188 // The failed purge attempt should have updated usage time to the correct | |
| 189 // value. | |
| 190 EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(3)); | |
| 191 | |
| 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)); | |
| 195 EXPECT_TRUE(rv); | |
| 196 EXPECT_TRUE(memory2.last_known_usage().is_null()); | |
| 197 | |
| 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)); | |
| 201 EXPECT_FALSE(rv); | |
| 202 | |
| 203 // The failed purge attempt should have updated usage time to the correct | |
| 204 // value. | |
| 205 EXPECT_TRUE(memory1.last_known_usage().is_null()); | |
| 206 | |
| 207 // Purge should succeed now that usage time is correct. | |
| 208 rv = memory1.Purge(Time::FromDoubleT(7)); | |
| 209 EXPECT_TRUE(rv); | |
| 210 } | |
| 211 | |
| 212 TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) { | |
| 213 const uint32 kDataSize = 1024; | |
| 214 | |
| 215 TestDiscardableSharedMemory memory1; | |
| 216 bool rv = memory1.CreateAndMap(kDataSize); | |
| 217 ASSERT_TRUE(rv); | |
| 218 | |
| 219 SharedMemoryHandle shared_handle; | |
| 220 ASSERT_TRUE( | |
| 221 memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); | |
| 222 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle)); | |
| 223 | |
| 224 TestDiscardableSharedMemory memory2(shared_handle); | |
| 225 rv = memory2.Map(kDataSize); | |
| 226 ASSERT_TRUE(rv); | |
| 227 | |
| 228 memory2.SetNow(Time::FromDoubleT(1)); | |
| 229 memory2.Unlock(0, 0); | |
| 230 | |
| 231 rv = memory2.Purge(Time::FromDoubleT(2)); | |
| 232 EXPECT_TRUE(rv); | |
| 233 | |
| 234 // Lock should fail as memory has been purged. | |
| 235 auto lock_rv = memory2.Lock(0, 0); | |
| 236 EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv); | |
| 237 } | |
| 238 | |
| 239 TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) { | |
| 240 const uint32 kDataSize = 32; | |
| 241 | |
| 242 uint32 data_size_in_bytes = kDataSize * base::GetPageSize(); | |
| 243 | |
| 244 TestDiscardableSharedMemory memory1; | |
| 245 bool rv = memory1.CreateAndMap(data_size_in_bytes); | |
| 246 ASSERT_TRUE(rv); | |
| 247 | |
| 248 SharedMemoryHandle shared_handle; | |
| 249 ASSERT_TRUE( | |
| 250 memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle)); | |
| 251 ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle)); | |
| 252 | |
| 253 TestDiscardableSharedMemory memory2(shared_handle); | |
| 254 rv = memory2.Map(data_size_in_bytes); | |
| 255 ASSERT_TRUE(rv); | |
| 256 | |
| 257 // Unlock first page. | |
| 258 memory2.SetNow(Time::FromDoubleT(1)); | |
| 259 memory2.Unlock(0, base::GetPageSize()); | |
| 260 | |
| 261 rv = memory1.Purge(Time::FromDoubleT(2)); | |
| 262 EXPECT_FALSE(rv); | |
| 263 | |
| 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); | |
| 268 | |
| 269 // Unlock first page. | |
| 270 memory2.SetNow(Time::FromDoubleT(4)); | |
| 271 memory2.Unlock(0, base::GetPageSize()); | |
| 272 | |
| 273 rv = memory1.Purge(Time::FromDoubleT(5)); | |
| 274 EXPECT_FALSE(rv); | |
| 275 | |
| 276 // Unlock second page. | |
| 277 memory2.SetNow(Time::FromDoubleT(6)); | |
| 278 memory2.Unlock(base::GetPageSize(), base::GetPageSize()); | |
| 279 | |
| 280 rv = memory1.Purge(Time::FromDoubleT(7)); | |
| 281 EXPECT_FALSE(rv); | |
| 282 | |
| 283 // Unlock anything onwards. | |
| 284 memory2.SetNow(Time::FromDoubleT(8)); | |
| 285 memory2.Unlock(2 * base::GetPageSize(), 0); | |
| 286 | |
| 287 // Memory is unlocked, but our usage timestamp is incorrect. | |
| 288 rv = memory1.Purge(Time::FromDoubleT(9)); | |
| 289 EXPECT_FALSE(rv); | |
| 290 | |
| 291 // The failed purge attempt should have updated usage time to the correct | |
| 292 // value. | |
| 293 EXPECT_EQ(Time::FromDoubleT(8), memory1.last_known_usage()); | |
| 294 | |
| 295 // Purge should now succeed. | |
| 296 rv = memory1.Purge(Time::FromDoubleT(10)); | |
| 297 EXPECT_TRUE(rv); | |
| 298 } | |
| 299 | |
| 300 TEST(DiscardableSharedMemoryTest, MappedSize) { | |
| 301 const uint32 kDataSize = 1024; | |
| 302 | |
| 303 TestDiscardableSharedMemory memory; | |
| 304 bool rv = memory.CreateAndMap(kDataSize); | |
| 305 ASSERT_TRUE(rv); | |
| 306 | |
| 307 EXPECT_LE(kDataSize, memory.mapped_size()); | |
| 308 | |
| 309 // Mapped size should be 0 after memory segment has been unmapped. | |
| 310 rv = memory.Unmap(); | |
| 311 EXPECT_TRUE(rv); | |
| 312 EXPECT_EQ(0u, memory.mapped_size()); | |
| 313 } | |
| 314 | |
| 315 TEST(DiscardableSharedMemoryTest, Close) { | |
| 316 const uint32 kDataSize = 1024; | |
| 317 | |
| 318 TestDiscardableSharedMemory memory; | |
| 319 bool rv = memory.CreateAndMap(kDataSize); | |
| 320 ASSERT_TRUE(rv); | |
| 321 | |
| 322 // Mapped size should be unchanged after memory segment has been closed. | |
| 323 memory.Close(); | |
| 324 EXPECT_LE(kDataSize, memory.mapped_size()); | |
| 325 | |
| 326 // Memory is initially locked. Unlock it. | |
| 327 memory.SetNow(Time::FromDoubleT(1)); | |
| 328 memory.Unlock(0, 0); | |
| 329 | |
| 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)); | |
| 334 memory.Unlock(0, 0); | |
| 335 } | |
| 336 | |
| 337 #if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING) | |
| 338 TEST(DiscardableSharedMemoryTest, Shrink) { | |
| 339 const uint32 kDataSize = 1024; | |
| 340 | |
| 341 TestDiscardableSharedMemory memory; | |
| 342 bool rv = memory.CreateAndMap(kDataSize); | |
| 343 ASSERT_TRUE(rv); | |
| 344 | |
| 345 EXPECT_NE(0u, memory.mapped_size()); | |
| 346 | |
| 347 // Mapped size should be 0 after shrinking memory segment. | |
| 348 memory.Shrink(); | |
| 349 EXPECT_EQ(0u, memory.mapped_size()); | |
| 350 } | |
| 351 #endif | |
| 352 | |
| 353 } // namespace | |
| 354 } // namespace base | |
| OLD | NEW |