summaryrefslogtreecommitdiff
path: root/third_party/base/allocator/partition_allocator/page_allocator_internals_posix.h
diff options
context:
space:
mode:
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.h187
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_