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

Unified Diff: base/memory/discardable_shared_memory.cc

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 11 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/memory/discardable_shared_memory.cc
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
deleted file mode 100644
index 4fd15185ebcf47588004b67697498dcb57e7e810..0000000000000000000000000000000000000000
--- a/base/memory/discardable_shared_memory.cc
+++ /dev/null
@@ -1,376 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/discardable_shared_memory.h"
-
-#if defined(OS_POSIX)
-#include <unistd.h>
-#endif
-
-#include <algorithm>
-
-#include "base/atomicops.h"
-#include "base/logging.h"
-#include "base/numerics/safe_math.h"
-#include "base/process/process_metrics.h"
-
-#if defined(OS_ANDROID)
-#include "third_party/ashmem/ashmem.h"
-#endif
-
-namespace base {
-namespace {
-
-// Use a machine-sized pointer as atomic type. It will use the Atomic32 or
-// Atomic64 routines, depending on the architecture.
-typedef intptr_t AtomicType;
-typedef uintptr_t UAtomicType;
-
-// Template specialization for timestamp serialization/deserialization. This
-// is used to serialize timestamps using Unix time on systems where AtomicType
-// does not have enough precision to contain a timestamp in the standard
-// serialized format.
-template <int>
-Time TimeFromWireFormat(int64 value);
-template <int>
-int64 TimeToWireFormat(Time time);
-
-// Serialize to Unix time when using 4-byte wire format.
-// Note: 19 January 2038, this will cease to work.
-template <>
-Time ALLOW_UNUSED_TYPE TimeFromWireFormat<4>(int64 value) {
- return value ? Time::UnixEpoch() + TimeDelta::FromSeconds(value) : Time();
-}
-template <>
-int64 ALLOW_UNUSED_TYPE TimeToWireFormat<4>(Time time) {
- return time > Time::UnixEpoch() ? (time - Time::UnixEpoch()).InSeconds() : 0;
-}
-
-// Standard serialization format when using 8-byte wire format.
-template <>
-Time ALLOW_UNUSED_TYPE TimeFromWireFormat<8>(int64 value) {
- return Time::FromInternalValue(value);
-}
-template <>
-int64 ALLOW_UNUSED_TYPE TimeToWireFormat<8>(Time time) {
- return time.ToInternalValue();
-}
-
-struct SharedState {
- enum LockState { UNLOCKED = 0, LOCKED = 1 };
-
- explicit SharedState(AtomicType ivalue) { value.i = ivalue; }
- SharedState(LockState lock_state, Time timestamp) {
- int64 wire_timestamp = TimeToWireFormat<sizeof(AtomicType)>(timestamp);
- DCHECK_GE(wire_timestamp, 0);
- DCHECK_EQ(lock_state & ~1, 0);
- value.u = (static_cast<UAtomicType>(wire_timestamp) << 1) | lock_state;
- }
-
- LockState GetLockState() const { return static_cast<LockState>(value.u & 1); }
-
- Time GetTimestamp() const {
- return TimeFromWireFormat<sizeof(AtomicType)>(value.u >> 1);
- }
-
- // Bit 1: Lock state. Bit is set when locked.
- // Bit 2..sizeof(AtomicType)*8: Usage timestamp. NULL time when locked or
- // purged.
- union {
- AtomicType i;
- UAtomicType u;
- } value;
-};
-
-// Shared state is stored at offset 0 in shared memory segments.
-SharedState* SharedStateFromSharedMemory(const SharedMemory& shared_memory) {
- DCHECK(shared_memory.memory());
- return static_cast<SharedState*>(shared_memory.memory());
-}
-
-// Round up |size| to a multiple of alignment, which must be a power of two.
-size_t Align(size_t alignment, size_t size) {
- DCHECK_EQ(alignment & (alignment - 1), 0u);
- return (size + alignment - 1) & ~(alignment - 1);
-}
-
-// Round up |size| to a multiple of page size.
-size_t AlignToPageSize(size_t size) {
- return Align(base::GetPageSize(), size);
-}
-
-} // namespace
-
-DiscardableSharedMemory::DiscardableSharedMemory()
- : mapped_size_(0), locked_page_count_(0) {
-}
-
-DiscardableSharedMemory::DiscardableSharedMemory(
- SharedMemoryHandle shared_memory_handle)
- : shared_memory_(shared_memory_handle, false),
- mapped_size_(0),
- locked_page_count_(0) {
-}
-
-DiscardableSharedMemory::~DiscardableSharedMemory() {
-}
-
-bool DiscardableSharedMemory::CreateAndMap(size_t size) {
- CheckedNumeric<size_t> checked_size = size;
- checked_size += AlignToPageSize(sizeof(SharedState));
- if (!checked_size.IsValid())
- return false;
-
- if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
- return false;
-
- mapped_size_ =
- shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
-
- locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
-#if DCHECK_IS_ON()
- for (size_t page = 0; page < locked_page_count_; ++page)
- locked_pages_.insert(page);
-#endif
-
- DCHECK(last_known_usage_.is_null());
- SharedState new_state(SharedState::LOCKED, Time());
- subtle::Release_Store(&SharedStateFromSharedMemory(shared_memory_)->value.i,
- new_state.value.i);
- return true;
-}
-
-bool DiscardableSharedMemory::Map(size_t size) {
- if (!shared_memory_.Map(AlignToPageSize(sizeof(SharedState)) + size))
- return false;
-
- mapped_size_ =
- shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
-
- locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
-#if DCHECK_IS_ON()
- for (size_t page = 0; page < locked_page_count_; ++page)
- locked_pages_.insert(page);
-#endif
-
- return true;
-}
-
-bool DiscardableSharedMemory::Unmap() {
- if (!shared_memory_.Unmap())
- return false;
-
- mapped_size_ = 0;
- return true;
-}
-
-DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
- size_t offset, size_t length) {
- DCHECK_EQ(AlignToPageSize(offset), offset);
- DCHECK_EQ(AlignToPageSize(length), length);
-
- // Calls to this function must be synchronized properly.
- DFAKE_SCOPED_LOCK(thread_collision_warner_);
-
- DCHECK(shared_memory_.memory());
-
- // We need to successfully acquire the platform independent lock before
- // individual pages can be locked.
- if (!locked_page_count_) {
- // Return false when instance has been purged or not initialized properly
- // by checking if |last_known_usage_| is NULL.
- if (last_known_usage_.is_null())
- return FAILED;
-
- SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
- SharedState new_state(SharedState::LOCKED, Time());
- SharedState result(subtle::Acquire_CompareAndSwap(
- &SharedStateFromSharedMemory(shared_memory_)->value.i,
- old_state.value.i,
- new_state.value.i));
- if (result.value.u != old_state.value.u) {
- // Update |last_known_usage_| in case the above CAS failed because of
- // an incorrect timestamp.
- last_known_usage_ = result.GetTimestamp();
- return FAILED;
- }
- }
-
- // Zero for length means "everything onward".
- if (!length)
- length = AlignToPageSize(mapped_size_) - offset;
-
- size_t start = offset / base::GetPageSize();
- size_t end = start + length / base::GetPageSize();
- DCHECK_LT(start, end);
- DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
-
- // Add pages to |locked_page_count_|.
- // Note: Locking a page that is already locked is an error.
- locked_page_count_ += end - start;
-#if DCHECK_IS_ON()
- // Detect incorrect usage by keeping track of exactly what pages are locked.
- for (auto page = start; page < end; ++page) {
- auto result = locked_pages_.insert(page);
- DCHECK(result.second);
- }
- DCHECK_EQ(locked_pages_.size(), locked_page_count_);
-#endif
-
-#if defined(OS_ANDROID)
- SharedMemoryHandle handle = shared_memory_.handle();
- if (SharedMemory::IsHandleValid(handle)) {
- if (ashmem_pin_region(
- handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
- return PURGED;
- }
- }
-#endif
-
- return SUCCESS;
-}
-
-void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
- DCHECK_EQ(AlignToPageSize(offset), offset);
- DCHECK_EQ(AlignToPageSize(length), length);
-
- // Calls to this function must be synchronized properly.
- DFAKE_SCOPED_LOCK(thread_collision_warner_);
-
- // Zero for length means "everything onward".
- if (!length)
- length = AlignToPageSize(mapped_size_) - offset;
-
- DCHECK(shared_memory_.memory());
-
-#if defined(OS_ANDROID)
- SharedMemoryHandle handle = shared_memory_.handle();
- if (SharedMemory::IsHandleValid(handle)) {
- if (ashmem_unpin_region(
- handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
- DPLOG(ERROR) << "ashmem_unpin_region() failed";
- }
- }
-#endif
-
- size_t start = offset / base::GetPageSize();
- size_t end = start + length / base::GetPageSize();
- DCHECK_LT(start, end);
- DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
-
- // Remove pages from |locked_page_count_|.
- // Note: Unlocking a page that is not locked is an error.
- DCHECK_GE(locked_page_count_, end - start);
- locked_page_count_ -= end - start;
-#if DCHECK_IS_ON()
- // Detect incorrect usage by keeping track of exactly what pages are locked.
- for (auto page = start; page < end; ++page) {
- auto erased_count = locked_pages_.erase(page);
- DCHECK_EQ(1u, erased_count);
- }
- DCHECK_EQ(locked_pages_.size(), locked_page_count_);
-#endif
-
- // Early out and avoid releasing the platform independent lock if some pages
- // are still locked.
- if (locked_page_count_)
- return;
-
- Time current_time = Now();
- DCHECK(!current_time.is_null());
-
- SharedState old_state(SharedState::LOCKED, Time());
- SharedState new_state(SharedState::UNLOCKED, current_time);
- // Note: timestamp cannot be NULL as that is a unique value used when
- // locked or purged.
- DCHECK(!new_state.GetTimestamp().is_null());
- // Timestamp precision should at least be accurate to the second.
- DCHECK_EQ((new_state.GetTimestamp() - Time::UnixEpoch()).InSeconds(),
- (current_time - Time::UnixEpoch()).InSeconds());
- SharedState result(subtle::Release_CompareAndSwap(
- &SharedStateFromSharedMemory(shared_memory_)->value.i,
- old_state.value.i,
- new_state.value.i));
-
- DCHECK_EQ(old_state.value.u, result.value.u);
-
- last_known_usage_ = current_time;
-}
-
-void* DiscardableSharedMemory::memory() const {
- return reinterpret_cast<uint8*>(shared_memory_.memory()) +
- AlignToPageSize(sizeof(SharedState));
-}
-
-bool DiscardableSharedMemory::Purge(Time current_time) {
- // Calls to this function must be synchronized properly.
- DFAKE_SCOPED_LOCK(thread_collision_warner_);
-
- // Early out if not mapped. This can happen if the segment was previously
- // unmapped using a call to Close().
- if (!shared_memory_.memory())
- return true;
-
- SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
- SharedState new_state(SharedState::UNLOCKED, Time());
- SharedState result(subtle::Acquire_CompareAndSwap(
- &SharedStateFromSharedMemory(shared_memory_)->value.i,
- old_state.value.i,
- new_state.value.i));
-
- // Update |last_known_usage_| to |current_time| if the memory is locked. This
- // allows the caller to determine if purging failed because last known usage
- // was incorrect or memory was locked. In the second case, the caller should
- // most likely wait for some amount of time before attempting to purge the
- // the memory again.
- if (result.value.u != old_state.value.u) {
- last_known_usage_ = result.GetLockState() == SharedState::LOCKED
- ? current_time
- : result.GetTimestamp();
- return false;
- }
-
- last_known_usage_ = Time();
- return true;
-}
-
-bool DiscardableSharedMemory::IsMemoryResident() const {
- DCHECK(shared_memory_.memory());
-
- SharedState result(subtle::NoBarrier_Load(
- &SharedStateFromSharedMemory(shared_memory_)->value.i));
-
- return result.GetLockState() == SharedState::LOCKED ||
- !result.GetTimestamp().is_null();
-}
-
-void DiscardableSharedMemory::Close() {
- shared_memory_.Close();
-}
-
-#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
-void DiscardableSharedMemory::Shrink() {
-#if defined(OS_POSIX)
- SharedMemoryHandle handle = shared_memory_.handle();
- if (!SharedMemory::IsHandleValid(handle))
- return;
-
- // Truncate shared memory to size of SharedState.
- if (HANDLE_EINTR(ftruncate(SharedMemory::GetFdFromSharedMemoryHandle(handle),
- AlignToPageSize(sizeof(SharedState)))) != 0) {
- DPLOG(ERROR) << "ftruncate() failed";
- return;
- }
- mapped_size_ = 0;
-#else
- NOTIMPLEMENTED();
-#endif
-}
-#endif
-
-Time DiscardableSharedMemory::Now() const {
- return Time::Now();
-}
-
-} // namespace base
« 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