diff options
Diffstat (limited to 'third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h')
-rw-r--r-- | third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h b/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h new file mode 100644 index 0000000000..0622222b53 --- /dev/null +++ b/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h @@ -0,0 +1,187 @@ +// Copyright (c) 2018 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. + +#ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_ +#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_ + +#include <errno.h> +#include <sys/mman.h> + +#include "build/build_config.h" + +#if defined(OS_MACOSX) +#include <mach/mach.h> +#endif +#if defined(OS_LINUX) +#include <sys/resource.h> + +#include <algorithm> +#endif + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +namespace pdfium { +namespace base { + +// |mmap| uses a nearby address if the hint address is blocked. +constexpr bool kHintIsAdvisory = true; +std::atomic<int32_t> s_allocPageErrorCode{0}; + +int GetAccessFlags(PageAccessibilityConfiguration accessibility) { + switch (accessibility) { + case PageRead: + return PROT_READ; + case PageReadWrite: + return PROT_READ | PROT_WRITE; + case PageReadExecute: + return PROT_READ | PROT_EXEC; + case PageReadWriteExecute: + return PROT_READ | PROT_WRITE | PROT_EXEC; + default: + NOTREACHED(); + FALLTHROUGH; + case PageInaccessible: + return PROT_NONE; + } +} + +#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS) + +// Multiple guarded memory regions may exceed the process address space limit. +// This function will raise or lower the limit by |amount|. +bool AdjustAddressSpaceLimit(int64_t amount) { + struct rlimit old_rlimit; + if (getrlimit(RLIMIT_AS, &old_rlimit)) + return false; + const rlim_t new_limit = + CheckAdd(old_rlimit.rlim_cur, amount).ValueOrDefault(old_rlimit.rlim_max); + const struct rlimit new_rlimit = {std::min(new_limit, old_rlimit.rlim_max), + old_rlimit.rlim_max}; + // setrlimit will fail if limit > old_rlimit.rlim_max. + return setrlimit(RLIMIT_AS, &new_rlimit) == 0; +} + +// Current WASM guarded memory regions have 8 GiB of address space. There are +// schemes that reduce that to 4 GiB. +constexpr size_t kMinimumGuardedMemorySize = 1ULL << 32; // 4 GiB + +#endif // defined(OS_LINUX) && defined(ARCH_CPU_64_BITS) + +void* SystemAllocPagesInternal(void* hint, + size_t length, + PageAccessibilityConfiguration accessibility, + PageTag page_tag, + bool commit) { +#if defined(OS_MACOSX) + // Use a custom tag to make it easier to distinguish Partition Alloc regions + // in vmmap(1). Tags between 240-255 are supported. + DCHECK(PageTag::kFirst <= page_tag); + DCHECK(PageTag::kLast >= page_tag); + int fd = VM_MAKE_TAG(static_cast<int>(page_tag)); +#else + int fd = -1; +#endif + + int access_flag = GetAccessFlags(accessibility); + void* ret = + mmap(hint, length, access_flag, MAP_ANONYMOUS | MAP_PRIVATE, fd, 0); + if (ret == MAP_FAILED) { + s_allocPageErrorCode = errno; + ret = nullptr; + } + return ret; +} + +void* TrimMappingInternal(void* base, + size_t base_length, + size_t trim_length, + PageAccessibilityConfiguration accessibility, + bool commit, + size_t pre_slack, + size_t post_slack) { + void* ret = base; + // We can resize the allocation run. Release unneeded memory before and after + // the aligned range. + if (pre_slack) { + int res = munmap(base, pre_slack); + CHECK(!res); + ret = reinterpret_cast<char*>(base) + pre_slack; + } + if (post_slack) { + int res = munmap(reinterpret_cast<char*>(ret) + trim_length, post_slack); + CHECK(!res); + } + return ret; +} + +bool SetSystemPagesAccessInternal( + void* address, + size_t length, + PageAccessibilityConfiguration accessibility) { + return 0 == mprotect(address, length, GetAccessFlags(accessibility)); +} + +void FreePagesInternal(void* address, size_t length) { + CHECK(!munmap(address, length)); + +#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS) + // Restore the address space limit. + if (length >= kMinimumGuardedMemorySize) { + CHECK(AdjustAddressSpaceLimit(-base::checked_cast<int64_t>(length))); + } +#endif +} + +void DecommitSystemPagesInternal(void* address, size_t length) { + // In POSIX, there is no decommit concept. Discarding is an effective way of + // implementing the Windows semantics where the OS is allowed to not swap the + // pages in the region. + // + // TODO(ajwong): Also explore setting PageInaccessible to make the protection + // semantics consistent between Windows and POSIX. This might have a perf cost + // though as both decommit and recommit would incur an extra syscall. + // http://crbug.com/766882 + DiscardSystemPages(address, length); +} + +bool RecommitSystemPagesInternal(void* address, + size_t length, + PageAccessibilityConfiguration accessibility) { +#if defined(OS_MACOSX) + // On macOS, to update accounting, we need to make another syscall. For more + // details, see https://crbug.com/823915. + madvise(address, length, MADV_FREE_REUSE); +#endif + + // On POSIX systems, the caller need simply read the memory to recommit it. + // This has the correct behavior because the API requires the permissions to + // be the same as before decommitting and all configurations can read. + return true; +} + +void DiscardSystemPagesInternal(void* address, size_t length) { +#if defined(OS_MACOSX) + int ret = madvise(address, length, MADV_FREE_REUSABLE); + if (ret) { + // MADV_FREE_REUSABLE sometimes fails, so fall back to MADV_DONTNEED. + ret = madvise(address, length, MADV_DONTNEED); + } + CHECK(0 == ret); +#else + // We have experimented with other flags, but with suboptimal results. + // + // MADV_FREE (Linux): Makes our memory measurements less predictable; + // performance benefits unclear. + // + // Therefore, we just do the simple thing: MADV_DONTNEED. + CHECK(!madvise(address, length, MADV_DONTNEED)); +#endif +} + +} // namespace base +} // namespace pdfium + +#endif // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_POSIX_H_ |