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

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

Issue 1409743002: Re-land: base: Use MADV_REMOVE instead of ftruncate to purge discardable memory segments. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add comment explaining the use of MADV_FREE Created 5 years, 2 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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_shared_memory.h" 5 #include "base/memory/discardable_shared_memory.h"
6 6
7 #if defined(OS_POSIX) 7 #if defined(OS_POSIX) && !defined(OS_NACL)
danakj 2015/10/20 18:04:03 I'm still kinda uncomfortable with this statement
reveman 2015/10/21 14:50:57 madvise() is part of the POSIX standard. It was ad
8 #include <unistd.h> 8 #include <sys/mman.h>
9 #endif 9 #endif
10 10
11 #include <algorithm> 11 #include <algorithm>
12 12
13 #include "base/atomicops.h" 13 #include "base/atomicops.h"
14 #include "base/bits.h" 14 #include "base/bits.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/numerics/safe_math.h" 16 #include "base/numerics/safe_math.h"
17 #include "base/process/process_metrics.h" 17 #include "base/process/process_metrics.h"
18 18
19 #if defined(OS_ANDROID) 19 #if defined(OS_ANDROID)
20 #include "third_party/ashmem/ashmem.h" 20 #include "third_party/ashmem/ashmem.h"
21 #endif 21 #endif
22 22
23 // Use MADV_FREE when MADV_REMOVE is not available. MADV_FREE doesn't give us
Primiano Tucci (use gerrit) 2015/10/20 13:33:39 I'd probably make this comment a bit more explicit
reveman 2015/10/21 14:50:57 Done.
24 // the guarantee that pages will be zero-filled after a call which makes it
25 // hard to test but it shouldn't hurt to use it. Worst case, it has the effect
26 // of not calling madvise.
27 #if !defined(DISCARDABLE_SHARED_MEMORY_REMOVE)
28 #define MADV_REMOVE MADV_FREE
29 #endif
30
23 namespace base { 31 namespace base {
24 namespace { 32 namespace {
25 33
26 // Use a machine-sized pointer as atomic type. It will use the Atomic32 or 34 // Use a machine-sized pointer as atomic type. It will use the Atomic32 or
27 // Atomic64 routines, depending on the architecture. 35 // Atomic64 routines, depending on the architecture.
28 typedef intptr_t AtomicType; 36 typedef intptr_t AtomicType;
29 typedef uintptr_t UAtomicType; 37 typedef uintptr_t UAtomicType;
30 38
31 // Template specialization for timestamp serialization/deserialization. This 39 // Template specialization for timestamp serialization/deserialization. This
32 // is used to serialize timestamps using Unix time on systems where AtomicType 40 // is used to serialize timestamps using Unix time on systems where AtomicType
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 } 302 }
295 303
296 void* DiscardableSharedMemory::memory() const { 304 void* DiscardableSharedMemory::memory() const {
297 return reinterpret_cast<uint8*>(shared_memory_.memory()) + 305 return reinterpret_cast<uint8*>(shared_memory_.memory()) +
298 AlignToPageSize(sizeof(SharedState)); 306 AlignToPageSize(sizeof(SharedState));
299 } 307 }
300 308
301 bool DiscardableSharedMemory::Purge(Time current_time) { 309 bool DiscardableSharedMemory::Purge(Time current_time) {
302 // Calls to this function must be synchronized properly. 310 // Calls to this function must be synchronized properly.
303 DFAKE_SCOPED_LOCK(thread_collision_warner_); 311 DFAKE_SCOPED_LOCK(thread_collision_warner_);
304 312 DCHECK(shared_memory_.memory());
305 // Early out if not mapped. This can happen if the segment was previously
306 // unmapped using a call to Close().
307 if (!shared_memory_.memory())
308 return true;
309 313
310 SharedState old_state(SharedState::UNLOCKED, last_known_usage_); 314 SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
311 SharedState new_state(SharedState::UNLOCKED, Time()); 315 SharedState new_state(SharedState::UNLOCKED, Time());
312 SharedState result(subtle::Acquire_CompareAndSwap( 316 SharedState result(subtle::Acquire_CompareAndSwap(
313 &SharedStateFromSharedMemory(shared_memory_)->value.i, 317 &SharedStateFromSharedMemory(shared_memory_)->value.i,
314 old_state.value.i, 318 old_state.value.i,
315 new_state.value.i)); 319 new_state.value.i));
316 320
317 // Update |last_known_usage_| to |current_time| if the memory is locked. This 321 // Update |last_known_usage_| to |current_time| if the memory is locked. This
318 // allows the caller to determine if purging failed because last known usage 322 // allows the caller to determine if purging failed because last known usage
319 // was incorrect or memory was locked. In the second case, the caller should 323 // was incorrect or memory was locked. In the second case, the caller should
320 // most likely wait for some amount of time before attempting to purge the 324 // most likely wait for some amount of time before attempting to purge the
321 // the memory again. 325 // the memory again.
322 if (result.value.u != old_state.value.u) { 326 if (result.value.u != old_state.value.u) {
323 last_known_usage_ = result.GetLockState() == SharedState::LOCKED 327 last_known_usage_ = result.GetLockState() == SharedState::LOCKED
324 ? current_time 328 ? current_time
325 : result.GetTimestamp(); 329 : result.GetTimestamp();
326 return false; 330 return false;
327 } 331 }
328 332
333 #if defined(OS_POSIX) && !defined(OS_NACL)
334 // Advise the kernel to remove resources associated with purged pages.
335 // Subsequent accesses of memory pages will succeed, but will result in
336 // zero-fill-on-demand pages.
337 if (madvise(reinterpret_cast<char*>(shared_memory_.memory()) +
338 AlignToPageSize(sizeof(SharedState)),
339 AlignToPageSize(mapped_size_), MADV_REMOVE)) {
340 DPLOG(ERROR) << "madvise(MADV_REMOVE) failed";
Primiano Tucci (use gerrit) 2015/10/20 13:33:39 On mac if this fails you will say that madvise(MAD
reveman 2015/10/21 14:50:57 Done.
341 }
342 #endif
343
329 last_known_usage_ = Time(); 344 last_known_usage_ = Time();
330 return true; 345 return true;
331 } 346 }
332 347
333 bool DiscardableSharedMemory::IsMemoryResident() const { 348 bool DiscardableSharedMemory::IsMemoryResident() const {
334 DCHECK(shared_memory_.memory()); 349 DCHECK(shared_memory_.memory());
335 350
336 SharedState result(subtle::NoBarrier_Load( 351 SharedState result(subtle::NoBarrier_Load(
337 &SharedStateFromSharedMemory(shared_memory_)->value.i)); 352 &SharedStateFromSharedMemory(shared_memory_)->value.i));
338 353
339 return result.GetLockState() == SharedState::LOCKED || 354 return result.GetLockState() == SharedState::LOCKED ||
340 !result.GetTimestamp().is_null(); 355 !result.GetTimestamp().is_null();
341 } 356 }
342 357
343 bool DiscardableSharedMemory::IsMemoryLocked() const { 358 bool DiscardableSharedMemory::IsMemoryLocked() const {
344 DCHECK(shared_memory_.memory()); 359 DCHECK(shared_memory_.memory());
345 360
346 SharedState result(subtle::NoBarrier_Load( 361 SharedState result(subtle::NoBarrier_Load(
347 &SharedStateFromSharedMemory(shared_memory_)->value.i)); 362 &SharedStateFromSharedMemory(shared_memory_)->value.i));
348 363
349 return result.GetLockState() == SharedState::LOCKED; 364 return result.GetLockState() == SharedState::LOCKED;
350 } 365 }
351 366
352 void DiscardableSharedMemory::Close() { 367 void DiscardableSharedMemory::Close() {
353 shared_memory_.Close(); 368 shared_memory_.Close();
354 } 369 }
355 370
356 #if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
357 void DiscardableSharedMemory::Shrink() {
358 #if defined(OS_POSIX)
359 SharedMemoryHandle handle = shared_memory_.handle();
360 if (!SharedMemory::IsHandleValid(handle))
361 return;
362
363 // Truncate shared memory to size of SharedState.
364 if (HANDLE_EINTR(ftruncate(SharedMemory::GetFdFromSharedMemoryHandle(handle),
365 AlignToPageSize(sizeof(SharedState)))) != 0) {
366 DPLOG(ERROR) << "ftruncate() failed";
367 return;
368 }
369 mapped_size_ = 0;
370 #else
371 NOTIMPLEMENTED();
372 #endif
373 }
374 #endif
375
376 Time DiscardableSharedMemory::Now() const { 371 Time DiscardableSharedMemory::Now() const {
377 return Time::Now(); 372 return Time::Now();
378 } 373 }
379 374
380 } // namespace base 375 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/discardable_shared_memory.h ('k') | base/memory/discardable_shared_memory_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698