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

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: fix problem with segment having been released before we try to purge 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)
8 #include <unistd.h> 8 // For madvise() which is available on all POSIX compatible systems.
9 #include <sys/mman.h>
9 #endif 10 #endif
10 11
11 #include <algorithm> 12 #include <algorithm>
12 13
13 #include "base/atomicops.h" 14 #include "base/atomicops.h"
14 #include "base/bits.h" 15 #include "base/bits.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/numerics/safe_math.h" 17 #include "base/numerics/safe_math.h"
17 #include "base/process/process_metrics.h" 18 #include "base/process/process_metrics.h"
18 19
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 } 295 }
295 296
296 void* DiscardableSharedMemory::memory() const { 297 void* DiscardableSharedMemory::memory() const {
297 return reinterpret_cast<uint8*>(shared_memory_.memory()) + 298 return reinterpret_cast<uint8*>(shared_memory_.memory()) +
298 AlignToPageSize(sizeof(SharedState)); 299 AlignToPageSize(sizeof(SharedState));
299 } 300 }
300 301
301 bool DiscardableSharedMemory::Purge(Time current_time) { 302 bool DiscardableSharedMemory::Purge(Time current_time) {
302 // Calls to this function must be synchronized properly. 303 // Calls to this function must be synchronized properly.
303 DFAKE_SCOPED_LOCK(thread_collision_warner_); 304 DFAKE_SCOPED_LOCK(thread_collision_warner_);
304 305 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 306
310 SharedState old_state(SharedState::UNLOCKED, last_known_usage_); 307 SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
311 SharedState new_state(SharedState::UNLOCKED, Time()); 308 SharedState new_state(SharedState::UNLOCKED, Time());
312 SharedState result(subtle::Acquire_CompareAndSwap( 309 SharedState result(subtle::Acquire_CompareAndSwap(
313 &SharedStateFromSharedMemory(shared_memory_)->value.i, 310 &SharedStateFromSharedMemory(shared_memory_)->value.i,
314 old_state.value.i, 311 old_state.value.i,
315 new_state.value.i)); 312 new_state.value.i));
316 313
317 // Update |last_known_usage_| to |current_time| if the memory is locked. This 314 // 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 315 // 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 316 // 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 317 // most likely wait for some amount of time before attempting to purge the
321 // the memory again. 318 // the memory again.
322 if (result.value.u != old_state.value.u) { 319 if (result.value.u != old_state.value.u) {
323 last_known_usage_ = result.GetLockState() == SharedState::LOCKED 320 last_known_usage_ = result.GetLockState() == SharedState::LOCKED
324 ? current_time 321 ? current_time
325 : result.GetTimestamp(); 322 : result.GetTimestamp();
326 return false; 323 return false;
327 } 324 }
328 325
326 #if defined(OS_POSIX) && !defined(OS_NACL)
327 // Linux and Android provide MADV_REMOVE which is preferred as it has a
328 // behavior that can be verified in tests. Other POSIX flavors (MacOSX, BSDs),
329 // provide MADV_FREE which has the same result but memory is purged lazily.
330 #if defined(OS_LINUX) || defined(OS_ANDROID)
331 #define MADV_PURGE_ARGUMENT MADV_REMOVE
332 #else
333 #define MADV_PURGE_ARGUMENT MADV_FREE
334 #endif
335 // Advise the kernel to remove resources associated with purged pages.
336 // Subsequent accesses of memory pages will succeed, but might result in
337 // zero-fill-on-demand pages.
338 if (madvise(reinterpret_cast<char*>(shared_memory_.memory()) +
339 AlignToPageSize(sizeof(SharedState)),
340 AlignToPageSize(mapped_size_), MADV_PURGE_ARGUMENT)) {
341 DPLOG(ERROR) << "madvise() failed";
342 }
343 #endif
344
329 last_known_usage_ = Time(); 345 last_known_usage_ = Time();
330 return true; 346 return true;
331 } 347 }
332 348
333 bool DiscardableSharedMemory::IsMemoryResident() const { 349 bool DiscardableSharedMemory::IsMemoryResident() const {
334 DCHECK(shared_memory_.memory()); 350 DCHECK(shared_memory_.memory());
335 351
336 SharedState result(subtle::NoBarrier_Load( 352 SharedState result(subtle::NoBarrier_Load(
337 &SharedStateFromSharedMemory(shared_memory_)->value.i)); 353 &SharedStateFromSharedMemory(shared_memory_)->value.i));
338 354
339 return result.GetLockState() == SharedState::LOCKED || 355 return result.GetLockState() == SharedState::LOCKED ||
340 !result.GetTimestamp().is_null(); 356 !result.GetTimestamp().is_null();
341 } 357 }
342 358
343 bool DiscardableSharedMemory::IsMemoryLocked() const { 359 bool DiscardableSharedMemory::IsMemoryLocked() const {
344 DCHECK(shared_memory_.memory()); 360 DCHECK(shared_memory_.memory());
345 361
346 SharedState result(subtle::NoBarrier_Load( 362 SharedState result(subtle::NoBarrier_Load(
347 &SharedStateFromSharedMemory(shared_memory_)->value.i)); 363 &SharedStateFromSharedMemory(shared_memory_)->value.i));
348 364
349 return result.GetLockState() == SharedState::LOCKED; 365 return result.GetLockState() == SharedState::LOCKED;
350 } 366 }
351 367
352 void DiscardableSharedMemory::Close() { 368 void DiscardableSharedMemory::Close() {
353 shared_memory_.Close(); 369 shared_memory_.Close();
354 } 370 }
355 371
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 { 372 Time DiscardableSharedMemory::Now() const {
377 return Time::Now(); 373 return Time::Now();
378 } 374 }
379 375
380 } // namespace base 376 } // 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