Commit ae5e45c0 authored by Alexandr Ilin's avatar Alexandr Ilin Committed by Commit Bot

Convert discardable shared memory to the new shared memory API

Bug: 826213
Change-Id: Ifa1d7e3fd3625ef0161073d594f3f48aada7b7c8
Reviewed-on: https://chromium-review.googlesource.com/1019448Reviewed-by: default avatarDavid Reveman <reveman@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Alexandr Ilin <alexilin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553472}
parent 5b0d48d5
......@@ -97,8 +97,9 @@ struct SharedState {
};
// Shared state is stored at offset 0 in shared memory segments.
SharedState* SharedStateFromSharedMemory(const SharedMemory& shared_memory) {
DCHECK(shared_memory.memory());
SharedState* SharedStateFromSharedMemory(
const WritableSharedMemoryMapping& shared_memory) {
DCHECK(shared_memory.IsValid());
return static_cast<SharedState*>(shared_memory.memory());
}
......@@ -107,39 +108,6 @@ size_t AlignToPageSize(size_t size) {
return bits::Align(size, base::GetPageSize());
}
// LockPages/UnlockPages are platform-native discardable page management
// helper functions. Both expect |offset| to be specified relative to the
// base address at which |memory| is mapped, and that |offset| and |length|
// are page-aligned by the caller.
#if defined(OS_ANDROID)
// Returns SUCCESS on platforms which do not support discardable pages.
DiscardableSharedMemory::LockResult LockPages(const SharedMemory& memory,
size_t offset,
size_t length) {
SharedMemoryHandle handle = memory.handle();
if (handle.IsValid()) {
int pin_result = ashmem_pin_region(handle.GetHandle(), offset, length);
if (pin_result == ASHMEM_WAS_PURGED)
return DiscardableSharedMemory::PURGED;
if (pin_result < 0)
return DiscardableSharedMemory::FAILED;
}
return DiscardableSharedMemory::SUCCESS;
}
#endif
// UnlockPages() is a no-op on platforms not supporting discardable pages.
void UnlockPages(const SharedMemory& memory, size_t offset, size_t length) {
#if defined(OS_ANDROID)
SharedMemoryHandle handle = memory.handle();
if (handle.IsValid()) {
int unpin_result = ashmem_unpin_region(handle.GetHandle(), offset, length);
DCHECK_EQ(0, unpin_result);
}
#endif
}
} // namespace
DiscardableSharedMemory::DiscardableSharedMemory()
......@@ -147,11 +115,10 @@ DiscardableSharedMemory::DiscardableSharedMemory()
}
DiscardableSharedMemory::DiscardableSharedMemory(
SharedMemoryHandle shared_memory_handle)
: shared_memory_(shared_memory_handle, false),
UnsafeSharedMemoryRegion shared_memory_region)
: shared_memory_region_(std::move(shared_memory_region)),
mapped_size_(0),
locked_page_count_(0) {
}
locked_page_count_(0) {}
DiscardableSharedMemory::~DiscardableSharedMemory() = default;
......@@ -161,11 +128,18 @@ bool DiscardableSharedMemory::CreateAndMap(size_t size) {
if (!checked_size.IsValid())
return false;
if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
shared_memory_region_ =
UnsafeSharedMemoryRegion::Create(checked_size.ValueOrDie());
if (!shared_memory_region_.IsValid())
return false;
shared_memory_mapping_ = shared_memory_region_.Map();
if (!shared_memory_mapping_.IsValid())
return false;
mapped_size_ =
shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
mapped_size_ = shared_memory_mapping_.mapped_size() -
AlignToPageSize(sizeof(SharedState));
locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
#if DCHECK_IS_ON()
......@@ -175,17 +149,24 @@ bool DiscardableSharedMemory::CreateAndMap(size_t size) {
DCHECK(last_known_usage_.is_null());
SharedState new_state(SharedState::LOCKED, Time());
subtle::Release_Store(&SharedStateFromSharedMemory(shared_memory_)->value.i,
new_state.value.i);
subtle::Release_Store(
&SharedStateFromSharedMemory(shared_memory_mapping_)->value.i,
new_state.value.i);
return true;
}
bool DiscardableSharedMemory::Map(size_t size) {
if (!shared_memory_.Map(AlignToPageSize(sizeof(SharedState)) + size))
DCHECK(!shared_memory_mapping_.IsValid());
if (shared_memory_mapping_.IsValid())
return false;
shared_memory_mapping_ = shared_memory_region_.MapAt(
0, AlignToPageSize(sizeof(SharedState)) + size);
if (!shared_memory_mapping_.IsValid())
return false;
mapped_size_ =
shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
mapped_size_ = shared_memory_mapping_.mapped_size() -
AlignToPageSize(sizeof(SharedState));
locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
#if DCHECK_IS_ON()
......@@ -197,9 +178,10 @@ bool DiscardableSharedMemory::Map(size_t size) {
}
bool DiscardableSharedMemory::Unmap() {
if (!shared_memory_.Unmap())
if (!shared_memory_mapping_.IsValid())
return false;
shared_memory_mapping_ = WritableSharedMemoryMapping();
locked_page_count_ = 0;
#if DCHECK_IS_ON()
locked_pages_.clear();
......@@ -216,7 +198,7 @@ DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
// Calls to this function must be synchronized properly.
DFAKE_SCOPED_LOCK(thread_collision_warner_);
DCHECK(shared_memory_.memory());
DCHECK(shared_memory_mapping_.IsValid());
// We need to successfully acquire the platform independent lock before
// individual pages can be locked.
......@@ -229,9 +211,8 @@ DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
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));
&SharedStateFromSharedMemory(shared_memory_mapping_)->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.
......@@ -267,7 +248,7 @@ DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
#if defined(OS_ANDROID)
// Ensure that the platform won't discard the required pages.
return LockPages(shared_memory_,
return LockPages(shared_memory_region_,
AlignToPageSize(sizeof(SharedState)) + offset, length);
#elif defined(OS_MACOSX)
// On macOS, there is no mechanism to lock pages. However, we do need to call
......@@ -283,7 +264,7 @@ DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
//
// For more information, see
// https://bugs.chromium.org/p/chromium/issues/detail?id=823915.
if (madvise(reinterpret_cast<char*>(shared_memory_.memory()) +
if (madvise(reinterpret_cast<char*>(shared_memory_mapping_.memory()) +
AlignToPageSize(sizeof(SharedState)),
AlignToPageSize(mapped_size_), MADV_FREE_REUSE))
;
......@@ -305,11 +286,11 @@ void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
if (!length)
length = AlignToPageSize(mapped_size_) - offset;
DCHECK(shared_memory_.memory());
DCHECK(shared_memory_mapping_.IsValid());
// Allow the pages to be discarded by the platform, if supported.
UnlockPages(shared_memory_, AlignToPageSize(sizeof(SharedState)) + offset,
length);
UnlockPages(shared_memory_region_,
AlignToPageSize(sizeof(SharedState)) + offset, length);
size_t start = offset / base::GetPageSize();
size_t end = start + length / base::GetPageSize();
......@@ -346,9 +327,8 @@ void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
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));
&SharedStateFromSharedMemory(shared_memory_mapping_)->value.i,
old_state.value.i, new_state.value.i));
DCHECK_EQ(old_state.value.u, result.value.u);
......@@ -356,21 +336,20 @@ void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
}
void* DiscardableSharedMemory::memory() const {
return reinterpret_cast<uint8_t*>(shared_memory_.memory()) +
return reinterpret_cast<uint8_t*>(shared_memory_mapping_.memory()) +
AlignToPageSize(sizeof(SharedState));
}
bool DiscardableSharedMemory::Purge(Time current_time) {
// Calls to this function must be synchronized properly.
DFAKE_SCOPED_LOCK(thread_collision_warner_);
DCHECK(shared_memory_.memory());
DCHECK(shared_memory_mapping_.IsValid());
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));
&SharedStateFromSharedMemory(shared_memory_mapping_)->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
......@@ -407,7 +386,7 @@ bool DiscardableSharedMemory::Purge(Time current_time) {
// Advise the kernel to remove resources associated with purged pages.
// Subsequent accesses of memory pages will succeed, but might result in
// zero-fill-on-demand pages.
if (madvise(reinterpret_cast<char*>(shared_memory_.memory()) +
if (madvise(reinterpret_cast<char*>(shared_memory_mapping_.memory()) +
AlignToPageSize(sizeof(SharedState)),
AlignToPageSize(mapped_size_), MADV_PURGE_ARGUMENT)) {
DPLOG(ERROR) << "madvise() failed";
......@@ -423,7 +402,7 @@ bool DiscardableSharedMemory::Purge(Time current_time) {
GetModuleHandle(L"kernel32.dll"), "DiscardVirtualMemory"));
if (discard_virtual_memory) {
DWORD discard_result = discard_virtual_memory(
reinterpret_cast<char*>(shared_memory_.memory()) +
reinterpret_cast<char*>(shared_memory_mapping_.memory()) +
AlignToPageSize(sizeof(SharedState)),
AlignToPageSize(mapped_size_));
if (discard_result != ERROR_SUCCESS) {
......@@ -439,34 +418,34 @@ bool DiscardableSharedMemory::Purge(Time current_time) {
}
bool DiscardableSharedMemory::IsMemoryResident() const {
DCHECK(shared_memory_.memory());
DCHECK(shared_memory_mapping_.IsValid());
SharedState result(subtle::NoBarrier_Load(
&SharedStateFromSharedMemory(shared_memory_)->value.i));
&SharedStateFromSharedMemory(shared_memory_mapping_)->value.i));
return result.GetLockState() == SharedState::LOCKED ||
!result.GetTimestamp().is_null();
}
bool DiscardableSharedMemory::IsMemoryLocked() const {
DCHECK(shared_memory_.memory());
DCHECK(shared_memory_mapping_.IsValid());
SharedState result(subtle::NoBarrier_Load(
&SharedStateFromSharedMemory(shared_memory_)->value.i));
&SharedStateFromSharedMemory(shared_memory_mapping_)->value.i));
return result.GetLockState() == SharedState::LOCKED;
}
void DiscardableSharedMemory::Close() {
shared_memory_.Close();
shared_memory_region_ = UnsafeSharedMemoryRegion();
}
void DiscardableSharedMemory::CreateSharedMemoryOwnershipEdge(
trace_event::MemoryAllocatorDump* local_segment_dump,
trace_event::ProcessMemoryDump* pmd,
bool is_owned) const {
auto* shared_memory_dump =
SharedMemoryTracker::GetOrCreateSharedMemoryDump(&shared_memory_, pmd);
auto* shared_memory_dump = SharedMemoryTracker::GetOrCreateSharedMemoryDump(
shared_memory_mapping_, pmd);
// TODO(ssid): Clean this by a new api to inherit size of parent dump once the
// we send the full PMD and calculate sizes inside chrome, crbug.com/704203.
size_t resident_size = shared_memory_dump->GetSizeInternal();
......@@ -480,7 +459,7 @@ void DiscardableSharedMemory::CreateSharedMemoryOwnershipEdge(
// TODO(ssid): Define better constants in MemoryAllocatorDump for importance
// values, crbug.com/754793.
const int kImportance = is_owned ? 2 : 0;
auto shared_memory_guid = shared_memory_.mapped_id();
auto shared_memory_guid = shared_memory_mapping_.guid();
local_segment_dump->AddString("id", "hash", shared_memory_guid.ToString());
// Owned discardable segments which are allocated by client process, could
......@@ -496,6 +475,38 @@ void DiscardableSharedMemory::CreateSharedMemoryOwnershipEdge(
}
}
// static
DiscardableSharedMemory::LockResult DiscardableSharedMemory::LockPages(
const UnsafeSharedMemoryRegion& region,
size_t offset,
size_t length) {
#if defined(OS_ANDROID)
if (region.IsValid()) {
int pin_result =
ashmem_pin_region(region.GetPlatformHandle(), offset, length);
if (pin_result == ASHMEM_WAS_PURGED)
return PURGED;
if (pin_result < 0)
return FAILED;
}
#endif
return SUCCESS;
}
// static
void DiscardableSharedMemory::UnlockPages(
const UnsafeSharedMemoryRegion& region,
size_t offset,
size_t length) {
#if defined(OS_ANDROID)
if (region.IsValid()) {
int unpin_result =
ashmem_unpin_region(region.GetPlatformHandle(), offset, length);
DCHECK_EQ(0, unpin_result);
}
#endif
}
Time DiscardableSharedMemory::Now() const {
return Time::Now();
}
......
......@@ -10,7 +10,8 @@
#include "base/base_export.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/threading/thread_collision_warner.h"
#include "base/time/time.h"
#include "build/build_config.h"
......@@ -49,7 +50,7 @@ class BASE_EXPORT DiscardableSharedMemory {
// Create a new DiscardableSharedMemory object from an existing, open shared
// memory file. Memory must be locked.
explicit DiscardableSharedMemory(SharedMemoryHandle handle);
explicit DiscardableSharedMemory(UnsafeSharedMemoryRegion region);
// Closes any open files.
virtual ~DiscardableSharedMemory();
......@@ -71,14 +72,17 @@ class BASE_EXPORT DiscardableSharedMemory {
// The actual size of the mapped memory (may be larger than requested).
size_t mapped_size() const { return mapped_size_; }
// Returns a shared memory handle for this DiscardableSharedMemory object.
SharedMemoryHandle handle() const { return shared_memory_.handle(); }
// Returns a duplicated shared memory region for this DiscardableSharedMemory
// object.
UnsafeSharedMemoryRegion DuplicateRegion() const {
return shared_memory_region_.Duplicate();
}
// Returns an ID for the shared memory region. This is ID of the mapped region
// consistent across all processes and is valid as long as the region is not
// unmapped.
const UnguessableToken& mapped_id() const {
return shared_memory_.mapped_id();
return shared_memory_mapping_.guid();
}
// Locks a range of memory so that it will not be purged by the system.
......@@ -147,10 +151,24 @@ class BASE_EXPORT DiscardableSharedMemory {
bool is_owned) const;
private:
// LockPages/UnlockPages are platform-native discardable page management
// helper functions. Both expect |offset| to be specified relative to the
// base address at which |memory| is mapped, and that |offset| and |length|
// are page-aligned by the caller.
// Returns SUCCESS on platforms which do not support discardable pages.
static LockResult LockPages(const UnsafeSharedMemoryRegion& region,
size_t offset,
size_t length);
// UnlockPages() is a no-op on platforms not supporting discardable pages.
static void UnlockPages(const UnsafeSharedMemoryRegion& region,
size_t offset,
size_t length);
// Virtual for tests.
virtual Time Now() const;
SharedMemory shared_memory_;
UnsafeSharedMemoryRegion shared_memory_region_;
WritableSharedMemoryMapping shared_memory_mapping_;
size_t mapped_size_;
size_t locked_page_count_;
#if DCHECK_IS_ON()
......
......@@ -15,14 +15,13 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
class TestDiscardableSharedMemory : public DiscardableSharedMemory {
public:
TestDiscardableSharedMemory() = default;
explicit TestDiscardableSharedMemory(SharedMemoryHandle handle)
: DiscardableSharedMemory(handle) {}
explicit TestDiscardableSharedMemory(UnsafeSharedMemoryRegion region)
: DiscardableSharedMemory(std::move(region)) {}
void SetNow(Time now) { now_ = now; }
......@@ -50,10 +49,10 @@ TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
bool rv = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
EXPECT_TRUE(memory2.IsMemoryLocked());
......@@ -82,10 +81,10 @@ TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
EXPECT_TRUE(memory1.IsMemoryLocked());
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -118,10 +117,10 @@ TEST(DiscardableSharedMemoryTest, Purge) {
bool rv = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -158,10 +157,10 @@ TEST(DiscardableSharedMemoryTest, LastUsed) {
bool rv = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -224,10 +223,10 @@ TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
bool rv = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -242,16 +241,22 @@ TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
}
#if defined(OS_ANDROID)
TEST(DiscardableSharedMemoryTest, LockShouldFailIfPlatformLockPagesFails) {
const uint32_t kDataSize = 1024;
DiscardableSharedMemory memory;
bool rv = memory.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
DiscardableSharedMemory memory1;
bool rv1 = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv1);
base::UnsafeSharedMemoryRegion region = memory1.DuplicateRegion();
int fd = region.GetPlatformHandle();
DiscardableSharedMemory memory2(std::move(region));
bool rv2 = memory2.Map(kDataSize);
ASSERT_TRUE(rv2);
// Unlock() the first page of memory, so we can test Lock()ing it.
memory.Unlock(0, base::GetPageSize());
#if defined(OS_ANDROID)
memory2.Unlock(0, base::GetPageSize());
// To cause ashmem_pin_region() to fail, we arrange for it to be called with
// an invalid file-descriptor, which requires a valid-looking fd (i.e. we
// can't just Close() |memory|), but one on which the operation is invalid.
......@@ -260,15 +265,14 @@ TEST(DiscardableSharedMemoryTest, LockShouldFailIfPlatformLockPagesFails) {
// that it can close, etc without errors, but on which ashmem_pin_region()
// will fail.
base::ScopedFD null(open("/dev/null", O_RDONLY));
ASSERT_EQ(memory.handle().GetHandle(),
dup2(null.get(), memory.handle().GetHandle()));
ASSERT_EQ(fd, dup2(null.get(), fd));
// Now re-Lock()ing the first page should fail.
DiscardableSharedMemory::LockResult lock_rv =
memory.Lock(0, base::GetPageSize());
memory2.Lock(0, base::GetPageSize());
EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
#endif // defined(OS_ANDROID)
}
#endif // defined(OS_ANDROID)
TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
const uint32_t kDataSize = 32;
......@@ -279,10 +283,10 @@ TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
bool rv = memory1.CreateAndMap(data_size_in_bytes);
ASSERT_TRUE(rv);
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(data_size_in_bytes);
ASSERT_TRUE(rv);
......@@ -396,10 +400,10 @@ TEST(DiscardableSharedMemoryTest, ZeroFilledPagesAfterPurge) {
bool rv = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
SharedMemoryHandle shared_handle = memory1.handle().Duplicate();
ASSERT_TRUE(shared_handle.IsValid());
UnsafeSharedMemoryRegion shared_region = memory1.DuplicateRegion();
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory2(shared_handle);
TestDiscardableSharedMemory memory2(std::move(shared_region));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -449,5 +453,4 @@ TEST(DiscardableSharedMemoryTest, TracingOwnershipEdges) {
// CreateWeakSharedMemoryOwnershipEdge() is fixed, crbug.com/661257.
}
} // namespace
} // namespace base
......@@ -44,6 +44,15 @@ SharedMemoryTracker::GetOrCreateSharedMemoryDump(
shared_memory->mapped_id(), pmd);
}
const trace_event::MemoryAllocatorDump*
SharedMemoryTracker::GetOrCreateSharedMemoryDump(
const SharedMemoryMapping& shared_memory,
trace_event::ProcessMemoryDump* pmd) {
return GetOrCreateSharedMemoryDumpInternal(shared_memory.raw_memory_ptr(),
shared_memory.mapped_size(),
shared_memory.guid(), pmd);
}
void SharedMemoryTracker::IncrementMemoryUsage(
const SharedMemory& shared_memory) {
AutoLock hold(usages_lock_);
......
......@@ -38,11 +38,14 @@ class BASE_EXPORT SharedMemoryTracker : public trace_event::MemoryDumpProvider {
static const trace_event::MemoryAllocatorDump* GetOrCreateSharedMemoryDump(
const SharedMemory* shared_memory,
trace_event::ProcessMemoryDump* pmd);
// We're in the middle of a refactor https://crbug.com/795291. Eventually, the
// first call will go away.
static const trace_event::MemoryAllocatorDump* GetOrCreateSharedMemoryDump(
const SharedMemoryMapping& shared_memory,
trace_event::ProcessMemoryDump* pmd);
// Records shared memory usage on valid mapping.
void IncrementMemoryUsage(const SharedMemory& shared_memory);
// We're in the middle of a refactor https://crbug.com/795291. Eventually, the
// first call will go away.
void IncrementMemoryUsage(const SharedMemoryMapping& mapping);
// Records shared memory usage on unmapping.
......
......@@ -5,6 +5,7 @@
#ifndef BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
#define BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/memory/shared_memory_mapping.h"
......@@ -88,8 +89,19 @@ class BASE_EXPORT UnsafeSharedMemoryRegion {
}
private:
FRIEND_TEST_ALL_PREFIXES(DiscardableSharedMemoryTest,
LockShouldFailIfPlatformLockPagesFails);
friend class DiscardableSharedMemory;
explicit UnsafeSharedMemoryRegion(subtle::PlatformSharedMemoryRegion handle);
// Returns a platform shared memory handle. |this| remains the owner of the
// handle.
subtle::PlatformSharedMemoryRegion::PlatformHandle GetPlatformHandle() const {
DCHECK(IsValid());
return handle_.GetPlatformHandle();
}
subtle::PlatformSharedMemoryRegion handle_;
DISALLOW_COPY_AND_ASSIGN(UnsafeSharedMemoryRegion);
......
......@@ -25,7 +25,6 @@
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "components/crash/core/common/crash_key.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace discardable_memory {
namespace {
......@@ -357,7 +356,7 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
"ClientDiscardableSharedMemoryManager::"
"AllocateLockedDiscardableSharedMemory",
"size", size, "id", id);
base::SharedMemoryHandle handle;
base::UnsafeSharedMemoryRegion region;
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
base::ScopedClosureRunner event_signal_runner(
......@@ -365,11 +364,12 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ClientDiscardableSharedMemoryManager::AllocateOnIO,
base::Unretained(this), size, id, &handle,
base::Unretained(this), size, id, &region,
std::move(event_signal_runner)));
// Waiting until IPC has finished on the IO thread.
event.Wait();
auto memory = std::make_unique<base::DiscardableSharedMemory>(handle);
auto memory =
std::make_unique<base::DiscardableSharedMemory>(std::move(region));
if (!memory->Map(size))
base::TerminateBecauseOutOfMemory(size);
return memory;
......@@ -378,25 +378,21 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
void ClientDiscardableSharedMemoryManager::AllocateOnIO(
size_t size,
int32_t id,
base::SharedMemoryHandle* handle,
base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner) {
(*manager_mojo_)
->AllocateLockedDiscardableSharedMemory(
static_cast<uint32_t>(size), id,
base::BindOnce(
&ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO,
base::Unretained(this), handle, std::move(closure_runner)));
base::Unretained(this), region, std::move(closure_runner)));
}
void ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO(
base::SharedMemoryHandle* handle,
base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner,
mojo::ScopedSharedBufferHandle mojo_handle) {
if (!mojo_handle.is_valid())
return;
auto result = mojo::UnwrapSharedMemoryHandle(std::move(mojo_handle), handle,
nullptr, nullptr);
DCHECK_EQ(result, MOJO_RESULT_OK);
base::UnsafeSharedMemoryRegion ret_region) {
*region = std::move(ret_region);
}
void ClientDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory(
......
......@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory_handle.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_provider.h"
#include "components/discardable_memory/common/discardable_memory_export.h"
......@@ -67,11 +67,11 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
AllocateLockedDiscardableSharedMemory(size_t size, int32_t id);
void AllocateOnIO(size_t size,
int32_t id,
base::SharedMemoryHandle* handle,
base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner);
void AllocateCompletedOnIO(base::SharedMemoryHandle* handle,
void AllocateCompletedOnIO(base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner,
mojo::ScopedSharedBufferHandle mojo_handle);
base::UnsafeSharedMemoryRegion ret_region);
void DeletedDiscardableSharedMemory(int32_t id);
void MemoryUsageChanged(size_t new_bytes_allocated,
......
......@@ -14,4 +14,8 @@ mojom("interfaces") {
get_path_info("../../../..", "abspath"),
"//mojo/services",
]
public_deps = [
"//mojo/public/mojom/base",
]
}
......@@ -4,13 +4,15 @@
module discardable_memory.mojom;
import "mojo/public/mojom/base/shared_memory.mojom";
// This interface is used for allocating discardable shared memory from browser
// process. For mus+ash, this service will live in mus process.
interface DiscardableSharedMemoryManager {
// Allocate a locked discardable shared memory segment.
AllocateLockedDiscardableSharedMemory(
uint32 size,
int32 id) => (handle<shared_buffer>? memory);
int32 id) => (mojo_base.mojom.UnsafeSharedMemoryRegion region);
// Notify manager that a memory segment has been deleted.
DeletedDiscardableSharedMemory(int32 id);
};
......@@ -31,7 +31,6 @@
#include "components/crash/core/common/crash_key.h"
#include "components/discardable_memory/common/discardable_shared_memory_heap.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
#if defined(OS_LINUX)
#include "base/files/file_path.h"
......@@ -69,16 +68,12 @@ class MojoDiscardableSharedMemoryManagerImpl
uint32_t size,
int32_t id,
AllocateLockedDiscardableSharedMemoryCallback callback) override {
base::SharedMemoryHandle handle;
mojo::ScopedSharedBufferHandle memory;
base::UnsafeSharedMemoryRegion region;
if (manager_) {
manager_->AllocateLockedDiscardableSharedMemoryForClient(client_id_, size,
id, &handle);
memory = mojo::WrapSharedMemoryHandle(
handle, size,
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
id, &region);
}
std::move(callback).Run(std::move(memory));
std::move(callback).Run(std::move(region));
}
void DeletedDiscardableSharedMemory(int32_t id) override {
......@@ -288,11 +283,11 @@ DiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(size_t size) {
// Note: Use DiscardableSharedMemoryHeap for in-process allocation
// of discardable memory if the cost of each allocation is too high.
base::SharedMemoryHandle handle;
base::UnsafeSharedMemoryRegion region;
AllocateLockedDiscardableSharedMemory(kInvalidUniqueClientID, size, new_id,
&handle);
&region);
std::unique_ptr<base::DiscardableSharedMemory> memory(
new base::DiscardableSharedMemory(handle));
new base::DiscardableSharedMemory(std::move(region)));
if (!memory->Map(size))
base::TerminateBecauseOutOfMemory(size);
// Close file descriptor to avoid running out.
......@@ -354,9 +349,9 @@ void DiscardableSharedMemoryManager::
int client_id,
size_t size,
int32_t id,
base::SharedMemoryHandle* shared_memory_handle) {
base::UnsafeSharedMemoryRegion* shared_memory_region) {
AllocateLockedDiscardableSharedMemory(client_id, size, id,
shared_memory_handle);
shared_memory_region);
}
void DiscardableSharedMemoryManager::ClientDeletedDiscardableSharedMemory(
......@@ -443,14 +438,14 @@ void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
int client_id,
size_t size,
int32_t id,
base::SharedMemoryHandle* shared_memory_handle) {
base::UnsafeSharedMemoryRegion* shared_memory_region) {
base::AutoLock lock(lock_);
// Make sure |id| is not already in use.
MemorySegmentMap& client_segments = clients_[client_id];
if (client_segments.find(id) != client_segments.end()) {
LOG(ERROR) << "Invalid discardable shared memory ID";
*shared_memory_handle = base::SharedMemoryHandle();
*shared_memory_region = base::UnsafeSharedMemoryRegion();
return;
}
......@@ -471,21 +466,21 @@ void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
std::unique_ptr<base::DiscardableSharedMemory> memory(
new base::DiscardableSharedMemory);
if (!memory->CreateAndMap(size)) {
*shared_memory_handle = base::SharedMemoryHandle();
*shared_memory_region = base::UnsafeSharedMemoryRegion();
return;
}
base::CheckedNumeric<size_t> checked_bytes_allocated = bytes_allocated_;
checked_bytes_allocated += memory->mapped_size();
if (!checked_bytes_allocated.IsValid()) {
*shared_memory_handle = base::SharedMemoryHandle();
*shared_memory_region = base::UnsafeSharedMemoryRegion();
return;
}
bytes_allocated_ = checked_bytes_allocated.ValueOrDie();
BytesAllocatedChanged(bytes_allocated_);
*shared_memory_handle = base::SharedMemory::DuplicateHandle(memory->handle());
*shared_memory_region = memory->DuplicateRegion();
// Close file descriptor to avoid running out.
memory->Close();
......
......@@ -20,7 +20,7 @@
#include "base/memory/memory_coordinator_client.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_current.h"
......@@ -68,12 +68,12 @@ class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryManager
base::trace_event::ProcessMemoryDump* pmd) override;
// This allocates a discardable memory segment for |process_handle|.
// A valid shared memory handle is returned on success.
// A valid shared memory region is returned on success.
void AllocateLockedDiscardableSharedMemoryForClient(
int client_id,
size_t size,
int32_t id,
base::SharedMemoryHandle* shared_memory_handle);
base::UnsafeSharedMemoryRegion* shared_memory_region);
// Call this to notify the manager that client process associated with
// |client_id| has deleted discardable memory segment with |id|.
......@@ -128,7 +128,7 @@ class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryManager
int client_id,
size_t size,
int32_t id,
base::SharedMemoryHandle* shared_memory_handle);
base::UnsafeSharedMemoryRegion* shared_memory_region);
void DeletedDiscardableSharedMemory(int32_t id, int client_id);
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
......
......@@ -20,8 +20,8 @@ class TestDiscardableSharedMemory : public base::DiscardableSharedMemory {
public:
TestDiscardableSharedMemory() {}
explicit TestDiscardableSharedMemory(base::SharedMemoryHandle handle)
: DiscardableSharedMemory(handle) {}
explicit TestDiscardableSharedMemory(base::UnsafeSharedMemoryRegion region)
: DiscardableSharedMemory(std::move(region)) {}
void SetNow(base::Time now) { now_ = now; }
......@@ -75,12 +75,12 @@ TEST_F(DiscardableSharedMemoryManagerTest, AllocateForClient) {
uint8_t data[kDataSize];
memset(data, 0x80, kDataSize);
base::SharedMemoryHandle shared_handle;
base::UnsafeSharedMemoryRegion shared_region;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 0, &shared_handle);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
kInvalidUniqueID, kDataSize, 0, &shared_region);
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory(shared_handle);
TestDiscardableSharedMemory memory(std::move(shared_region));
bool rv = memory.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -96,21 +96,21 @@ TEST_F(DiscardableSharedMemoryManagerTest, AllocateForClient) {
TEST_F(DiscardableSharedMemoryManagerTest, Purge) {
const int kDataSize = 1024;
base::SharedMemoryHandle shared_handle1;
base::UnsafeSharedMemoryRegion shared_region1;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 1, &shared_handle1);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1));
kInvalidUniqueID, kDataSize, 1, &shared_region1);
ASSERT_TRUE(shared_region1.IsValid());
TestDiscardableSharedMemory memory1(shared_handle1);
TestDiscardableSharedMemory memory1(std::move(shared_region1));
bool rv = memory1.Map(kDataSize);
ASSERT_TRUE(rv);
base::SharedMemoryHandle shared_handle2;
base::UnsafeSharedMemoryRegion shared_region2;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 2, &shared_handle2);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2));
kInvalidUniqueID, kDataSize, 2, &shared_region2);
ASSERT_TRUE(shared_region2.IsValid());
TestDiscardableSharedMemory memory2(shared_handle2);
TestDiscardableSharedMemory memory2(std::move(shared_region2));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -160,12 +160,12 @@ TEST_F(DiscardableSharedMemoryManagerTest, Purge) {
TEST_F(DiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) {
const int kDataSize = 1024;
base::SharedMemoryHandle shared_handle;
base::UnsafeSharedMemoryRegion shared_region;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 0, &shared_handle);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
kInvalidUniqueID, kDataSize, 0, &shared_region);
ASSERT_TRUE(shared_region.IsValid());
TestDiscardableSharedMemory memory(shared_handle);
TestDiscardableSharedMemory memory(std::move(shared_region));
bool rv = memory.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -198,21 +198,21 @@ TEST_F(DiscardableSharedMemoryManagerTest,
ReduceMemoryAfterSegmentHasBeenDeleted) {
const int kDataSize = 1024;
base::SharedMemoryHandle shared_handle1;
base::UnsafeSharedMemoryRegion shared_region1;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 1, &shared_handle1);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1));
kInvalidUniqueID, kDataSize, 1, &shared_region1);
ASSERT_TRUE(shared_region1.IsValid());
TestDiscardableSharedMemory memory1(shared_handle1);
TestDiscardableSharedMemory memory1(std::move(shared_region1));
bool rv = memory1.Map(kDataSize);
ASSERT_TRUE(rv);
base::SharedMemoryHandle shared_handle2;
base::UnsafeSharedMemoryRegion shared_region2;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 2, &shared_handle2);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2));
kInvalidUniqueID, kDataSize, 2, &shared_region2);
ASSERT_TRUE(shared_region2.IsValid());
TestDiscardableSharedMemory memory2(shared_handle2);
TestDiscardableSharedMemory memory2(std::move(shared_region2));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
......@@ -261,10 +261,10 @@ TEST_F(DiscardableSharedMemoryManagerScheduleEnforceMemoryPolicyTest,
SetMemoryLimitOnSimpleThread) {
const int kDataSize = 1024;
base::SharedMemoryHandle shared_handle;
base::UnsafeSharedMemoryRegion shared_region;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
kInvalidUniqueID, kDataSize, 0, &shared_handle);
ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
kInvalidUniqueID, kDataSize, 0, &shared_region);
ASSERT_TRUE(shared_region.IsValid());
// Set the memory limit to a value that will require EnforceMemoryPolicy()
// to be schedule on a thread without a message loop.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment