Introduce base::PageAllocator to wrap mmap
Gets rid of the various posix_memalign hacks accumulated so far.
Also moves the pre-existing IsMmaped function into
base/vm_test_utils.h.
Change-Id: I171dc2dc01c4b69f4f711a4923a1a58c75431df6
diff --git a/Android.bp b/Android.bp
index 9b815dd..75dd1c3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -571,6 +571,7 @@
":perfetto_protos_zero_gen",
":perfetto_src_ipc_wire_protocol_gen",
"src/base/android_task_runner.cc",
+ "src/base/page_allocator.cc",
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
"src/ftrace_reader/cpu_reader.cc",
@@ -639,6 +640,7 @@
":perfetto_protos_zero_gen",
":perfetto_src_ipc_wire_protocol_gen",
"src/base/android_task_runner.cc",
+ "src/base/page_allocator.cc",
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
"src/ipc/buffered_frame_deserializer.cc",
@@ -707,9 +709,12 @@
":perfetto_src_protozero_testing_messages_lite_gen",
":perfetto_src_protozero_testing_messages_zero_gen",
"src/base/android_task_runner.cc",
+ "src/base/page_allocator.cc",
+ "src/base/page_allocator_unittest.cc",
"src/base/scoped_file_unittest.cc",
"src/base/task_runner_unittest.cc",
"src/base/test/test_task_runner.cc",
+ "src/base/test/vm_test_utils.cc",
"src/base/thread_checker.cc",
"src/base/thread_checker_unittest.cc",
"src/base/unix_task_runner.cc",
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index 14bfc2f..d1d188a 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -16,6 +16,7 @@
sources = [
"build_config.h",
"logging.h",
+ "page_allocator.h",
"scoped_file.h",
"task_runner.h",
"thread_checker.h",
diff --git a/include/perfetto/base/page_allocator.h b/include/perfetto/base/page_allocator.h
new file mode 100644
index 0000000..05ad3ca
--- /dev/null
+++ b/include/perfetto/base/page_allocator.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_BASE_PAGE_ALLOCATOR_H_
+#define INCLUDE_PERFETTO_BASE_PAGE_ALLOCATOR_H_
+
+#include <memory>
+
+namespace perfetto {
+namespace base {
+
+class PageAllocator {
+ public:
+ class Deleter {
+ public:
+ Deleter();
+ explicit Deleter(size_t);
+ void operator()(void*) const;
+
+ private:
+ size_t size_;
+ };
+
+ using UniquePtr = std::unique_ptr<void, Deleter>;
+
+ // Allocates |size| bytes using mmap(MAP_ANONYMOUS). The returned pointer is
+ // guaranteed to be page-aligned and the memory is guaranteed to be zeroed.
+ // |size| must be a multiple of 4KB (a page size). Crashes if the underlying
+ // mmap() fails.
+ static UniquePtr Allocate(size_t size);
+
+ // Like the above, but returns a nullptr if the mmap() fails (e.g., if out
+ // of virtual address space).
+ static UniquePtr AllocateMayFail(size_t size);
+};
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_BASE_PAGE_ALLOCATOR_H_
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index b91fccb..3a8a851 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -22,6 +22,7 @@
"../../include/perfetto/base",
]
sources = [
+ "page_allocator.cc",
"thread_checker.cc",
"unix_task_runner.cc",
]
@@ -51,10 +52,13 @@
deps = [
":base",
"../../gn:default_deps",
+ "../../gn:gtest_deps",
]
sources = [
"test/test_task_runner.cc",
"test/test_task_runner.h",
+ "test/vm_test_utils.cc",
+ "test/vm_test_utils.h",
]
}
@@ -67,6 +71,7 @@
"../../gn:gtest_deps",
]
sources = [
+ "page_allocator_unittest.cc",
"scoped_file_unittest.cc",
"task_runner_unittest.cc",
"thread_checker_unittest.cc",
diff --git a/src/base/page_allocator.cc b/src/base/page_allocator.cc
new file mode 100644
index 0000000..a966b04
--- /dev/null
+++ b/src/base/page_allocator.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/base/page_allocator.h"
+
+#include <sys/mman.h>
+
+#include "perfetto/base/logging.h"
+
+namespace perfetto {
+namespace base {
+
+namespace {
+
+static constexpr size_t kPageSize = 4096;
+static constexpr size_t kGuardSize = kPageSize;
+
+// static
+PageAllocator::UniquePtr AllocateInternal(size_t size, bool unchecked) {
+ PERFETTO_DCHECK(size % kPageSize == 0);
+ size_t outer_size = size + kGuardSize * 2;
+ void* ptr = mmap(nullptr, outer_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ if (ptr == MAP_FAILED && unchecked)
+ return nullptr;
+ PERFETTO_CHECK(ptr && ptr != MAP_FAILED);
+ char* usable_region = reinterpret_cast<char*>(ptr) + kGuardSize;
+ int res = mprotect(ptr, kGuardSize, PROT_NONE);
+ res |= mprotect(usable_region + size, kGuardSize, PROT_NONE);
+ PERFETTO_CHECK(res == 0);
+ return PageAllocator::UniquePtr(usable_region, PageAllocator::Deleter(size));
+}
+
+} // namespace
+
+PageAllocator::Deleter::Deleter() : Deleter(0) {}
+PageAllocator::Deleter::Deleter(size_t size) : size_(size) {}
+
+void PageAllocator::Deleter::operator()(void* ptr) const {
+ if (!ptr)
+ return;
+ PERFETTO_CHECK(size_);
+ char* start = reinterpret_cast<char*>(ptr) - kGuardSize;
+ const size_t outer_size = size_ + kGuardSize * 2;
+ int res = munmap(start, outer_size);
+ PERFETTO_CHECK(res == 0);
+}
+
+// static
+PageAllocator::UniquePtr PageAllocator::Allocate(size_t size) {
+ return AllocateInternal(size, false /*unchecked*/);
+}
+
+// static
+PageAllocator::UniquePtr PageAllocator::AllocateMayFail(size_t size) {
+ return AllocateInternal(size, true /*unchecked*/);
+}
+
+} // namespace base
+} // namespace perfetto
diff --git a/src/base/page_allocator_unittest.cc b/src/base/page_allocator_unittest.cc
new file mode 100644
index 0000000..8737569
--- /dev/null
+++ b/src/base/page_allocator_unittest.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/base/page_allocator.h"
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include "gtest/gtest.h"
+#include "perfetto/base/build_config.h"
+#include "src/base/test/vm_test_utils.h"
+
+#if !BUILDFLAG(OS_MACOSX)
+#include <sys/resource.h>
+#endif
+
+namespace perfetto {
+namespace base {
+namespace {
+
+TEST(PageAllocatorTest, Basic) {
+ const size_t kNumPages = 10;
+ const size_t kSize = 4096 * kNumPages;
+ void* ptr_raw = nullptr;
+ {
+ PageAllocator::UniquePtr ptr = PageAllocator::Allocate(kSize);
+ ASSERT_TRUE(ptr);
+ ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(ptr.get()) % 4096);
+ ptr_raw = ptr.get();
+ for (size_t i = 0; i < kSize / sizeof(uint64_t); i++)
+ ASSERT_EQ(0u, *(reinterpret_cast<uint64_t*>(ptr.get()) + i));
+
+ ASSERT_TRUE(vm_test_utils::IsMapped(ptr_raw, kSize));
+ }
+
+ ASSERT_FALSE(vm_test_utils::IsMapped(ptr_raw, kSize));
+}
+
+TEST(PageAllocatorTest, GuardRegions) {
+ const size_t kSize = 4096;
+ PageAllocator::UniquePtr ptr = PageAllocator::Allocate(kSize);
+ ASSERT_TRUE(ptr);
+ volatile char* raw = reinterpret_cast<char*>(ptr.get());
+ EXPECT_DEATH({ raw[-1] = 'x'; }, ".*");
+ EXPECT_DEATH({ raw[kSize] = 'x'; }, ".*");
+}
+
+// Disable this on:
+// MacOS: because it doesn't seem to have an equivalent rlimit to bound mmap().
+// Sanitizers: they seem to try to shadow mmaped memory and fail due to OOMs.
+#if !BUILDFLAG(OS_MACOSX) && !defined(ADDRESS_SANITIZER) && \
+ !defined(LEAK_SANITIZER) && !defined(THREAD_SANITIZER) && \
+ !defined(MEMORY_SANITIZER)
+// Glibc headers hit this on RLIMIT_ macros.
+#pragma GCC diagnostic push
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
+#endif
+TEST(PageAllocatorTest, Unchecked) {
+ const size_t kMemLimit = 256 * 1024 * 1024l;
+ struct rlimit limit {
+ kMemLimit, kMemLimit
+ };
+ // ASSERT_EXIT here is to spawn the test in a sub-process and avoid
+ // propagating the setrlimit() to other test units in case of failure.
+ ASSERT_EXIT(
+ {
+ ASSERT_EQ(0, setrlimit(RLIMIT_AS, &limit));
+ auto ptr = PageAllocator::AllocateMayFail(kMemLimit * 2);
+ ASSERT_FALSE(ptr);
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+}
+#pragma GCC diagnostic pop
+#endif
+
+} // namespace
+} // namespace base
+} // namespace perfetto
diff --git a/src/base/test/vm_test_utils.cc b/src/base/test/vm_test_utils.cc
new file mode 100644
index 0000000..7980b51
--- /dev/null
+++ b/src/base/test/vm_test_utils.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/base/test/vm_test_utils.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "gtest/gtest.h"
+#include "perfetto/base/build_config.h"
+
+namespace perfetto {
+namespace base {
+namespace vm_test_utils {
+
+bool IsMapped(void* start, size_t size) {
+#if BUILDFLAG(OS_MACOSX)
+ using PageState = char;
+#else
+ using PageState = unsigned char;
+#endif
+ EXPECT_EQ(0u, size % 4096);
+ const size_t num_pages = size / 4096;
+ std::unique_ptr<PageState[]> page_states(new PageState[num_pages]);
+ memset(page_states.get(), 0, num_pages * sizeof(PageState));
+ int res = mincore(start, size, page_states.get());
+ // Linux returns ENOMEM when an unmapped memory range is passed.
+ // MacOS instead returns 0 but leaves the page_states empty.
+ if (res == -1 && errno == ENOMEM)
+ return false;
+ EXPECT_EQ(0, res);
+ for (size_t i = 0; i < num_pages; i++) {
+ if (!page_states[i])
+ return false;
+ }
+ return true;
+}
+
+} // namespace vm_test_utils
+} // namespace base
+} // namespace perfetto
diff --git a/src/base/test/vm_test_utils.h b/src/base/test/vm_test_utils.h
new file mode 100644
index 0000000..3e057cb
--- /dev/null
+++ b/src/base/test/vm_test_utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_BASE_TEST_VM_TEST_UTILS_H_
+#define SRC_BASE_TEST_VM_TEST_UTILS_H_
+
+#include <stddef.h>
+
+namespace perfetto {
+namespace base {
+namespace vm_test_utils {
+
+bool IsMapped(void* start, size_t size);
+
+} // namespace vm_test_utils
+} // namespace base
+} // namespace perfetto
+
+#endif // SRC_BASE_TEST_VM_TEST_UTILS_H_
diff --git a/src/ipc/buffered_frame_deserializer.cc b/src/ipc/buffered_frame_deserializer.cc
index 0f40186..38a8f45 100644
--- a/src/ipc/buffered_frame_deserializer.cc
+++ b/src/ipc/buffered_frame_deserializer.cc
@@ -17,7 +17,6 @@
#include "src/ipc/buffered_frame_deserializer.h"
#include <inttypes.h>
-#include <sys/mman.h>
#include <algorithm>
#include <type_traits>
@@ -25,7 +24,6 @@
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include "perfetto/base/logging.h"
-#include "perfetto/base/utils.h"
#include "src/ipc/wire_protocol.pb.h"
@@ -35,10 +33,6 @@
namespace {
constexpr size_t kPageSize = 4096;
-// Size of the PROT_NONE guard region, adjactent to the end of the buffer.
-// It's a safety net to spot any out-of-bounds writes early.
-constexpr size_t kGuardRegionSize = kPageSize;
-
// The header is just the number of bytes of the Frame protobuf message.
constexpr size_t kHeaderSize = sizeof(uint32_t);
} // namespace
@@ -49,12 +43,7 @@
PERFETTO_CHECK(max_capacity > kPageSize);
}
-BufferedFrameDeserializer::~BufferedFrameDeserializer() {
- if (!buf_)
- return;
- int res = munmap(buf_, capacity_ + kGuardRegionSize);
- PERFETTO_DCHECK(res == 0);
-}
+BufferedFrameDeserializer::~BufferedFrameDeserializer() = default;
BufferedFrameDeserializer::ReceiveBuffer
BufferedFrameDeserializer::BeginReceive() {
@@ -63,24 +52,17 @@
// automatically give us physical pages back as soon as we page-fault on them.
if (!buf_) {
PERFETTO_DCHECK(size_ == 0);
- buf_ = reinterpret_cast<char*>(mmap(nullptr, capacity_ + kGuardRegionSize,
- PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
- PERFETTO_CHECK(buf_ != MAP_FAILED);
+ buf_ = base::PageAllocator::Allocate(capacity_);
// Surely we are going to use at least the first page. There is very little
// point in madvising that as well and immedately after telling the kernel
// that we want it back (via recv()).
- int res = madvise(buf_ + kPageSize,
- capacity_ + kGuardRegionSize - kPageSize, MADV_DONTNEED);
- PERFETTO_DCHECK(res == 0);
-
- res = mprotect(buf_ + capacity_, kGuardRegionSize, PROT_NONE);
+ int res = madvise(buf() + kPageSize, capacity_ - kPageSize, MADV_DONTNEED);
PERFETTO_DCHECK(res == 0);
}
PERFETTO_CHECK(capacity_ > size_);
- return ReceiveBuffer{buf_ + size_, capacity_ - size_};
+ return ReceiveBuffer{buf() + size_, capacity_ - size_};
}
bool BufferedFrameDeserializer::EndReceive(size_t recv_size) {
@@ -114,7 +96,7 @@
// Read the header into |payload_size|.
uint32_t payload_size = 0;
- const char* rd_ptr = buf_ + consumed_size;
+ const char* rd_ptr = buf() + consumed_size;
memcpy(base::AssumeLittleEndian(&payload_size), rd_ptr, kHeaderSize);
// Saturate the |payload_size| to prevent overflows. The > capacity_ check
@@ -151,10 +133,10 @@
// Case D. We consumed some frames but there is a leftover at the end of
// the buffer. Shift out the consumed bytes, so that on the next round
// |buf_| starts with the header of the next unconsumed frame.
- const char* move_begin = buf_ + consumed_size;
- PERFETTO_CHECK(move_begin > buf_);
- PERFETTO_CHECK(move_begin + size_ <= buf_ + capacity_);
- memmove(buf_, move_begin, size_);
+ const char* move_begin = buf() + consumed_size;
+ PERFETTO_CHECK(move_begin > buf());
+ PERFETTO_CHECK(move_begin + size_ <= buf() + capacity_);
+ memmove(buf(), move_begin, size_);
}
// If we just finished decoding a large frame that used more than one page,
// release the extra memory in the buffer. Large frames should be quite
@@ -162,10 +144,10 @@
if (consumed_size > kPageSize) {
size_t size_rounded_up = (size_ / kPageSize + 1) * kPageSize;
if (size_rounded_up < capacity_) {
- char* madvise_begin = buf_ + size_rounded_up;
+ char* madvise_begin = buf() + size_rounded_up;
const size_t madvise_size = capacity_ - size_rounded_up;
- PERFETTO_CHECK(madvise_begin > buf_ + size_);
- PERFETTO_CHECK(madvise_begin + madvise_size <= buf_ + capacity_);
+ PERFETTO_CHECK(madvise_begin > buf() + size_);
+ PERFETTO_CHECK(madvise_begin + madvise_size <= buf() + capacity_);
int res = madvise(madvise_begin, madvise_size, MADV_DONTNEED);
PERFETTO_DCHECK(res == 0);
}
diff --git a/src/ipc/buffered_frame_deserializer.h b/src/ipc/buffered_frame_deserializer.h
index 874a7a2..40e1a64 100644
--- a/src/ipc/buffered_frame_deserializer.h
+++ b/src/ipc/buffered_frame_deserializer.h
@@ -22,7 +22,9 @@
#include <list>
#include <memory>
-#include "perfetto/base/utils.h"
+#include <sys/mman.h>
+
+#include "perfetto/base/page_allocator.h"
namespace perfetto {
namespace ipc {
@@ -113,8 +115,10 @@
// If a valid frame is decoded it is added to |decoded_frames_|.
void DecodeFrame(const char*, size_t);
- char* buf_ = nullptr;
- const size_t capacity_ = 0; // sizeof(|buf_|), excluding the guard region.
+ char* buf() { return reinterpret_cast<char*>(buf_.get()); }
+
+ base::PageAllocator::UniquePtr buf_;
+ const size_t capacity_ = 0; // sizeof(|buf_|).
// THe number of bytes in |buf_| that contain valid data (as a result of
// EndReceive()). This is always <= |capacity_|.
diff --git a/src/tracing/core/service_impl.cc b/src/tracing/core/service_impl.cc
index b0cc33c..f1c92ee 100644
--- a/src/tracing/core/service_impl.cc
+++ b/src/tracing/core/service_impl.cc
@@ -135,7 +135,12 @@
}
PERFETTO_DCHECK(ts.trace_buffers.count(id) == 0);
// TODO(primiano): make TraceBuffer::kBufferPageSize dynamic.
- ts.trace_buffers.emplace(id, TraceBuffer(buffer_cfg.size_kb() * 1024u));
+ const size_t buf_size = buffer_cfg.size_kb() * 1024u;
+ auto it_and_inserted = ts.trace_buffers.emplace(id, TraceBuffer(buf_size));
+ if (!it_and_inserted.second || !it_and_inserted.first->second.is_valid()) {
+ did_allocate_all_buffers = false;
+ break;
+ }
}
// This can happen if all the kMaxTraceBuffers slots are taken (i.e. we are
@@ -439,17 +444,13 @@
////////////////////////////////////////////////////////////////////////////////
ServiceImpl::TraceBuffer::TraceBuffer(size_t sz) : size(sz) {
- void* ptr = nullptr;
- PERFETTO_CHECK(size % kBufferPageSize == 0);
- // TODO(primiano): introduce base::PageAllocator and use mmap() instead.
- if (posix_memalign(&ptr, kPageSize, size)) {
+ data = base::PageAllocator::AllocateMayFail(size);
+ if (!data) {
PERFETTO_ELOG("Trace buffer allocation failed (size: %zu, page_size: %zu)",
size, kBufferPageSize);
+ size = 0;
return;
}
- PERFETTO_CHECK(ptr);
- memset(ptr, 0, size);
- data.reset(ptr);
abi.reset(new SharedMemoryABI(get_page(0), size, kBufferPageSize));
}
diff --git a/src/tracing/core/service_impl.h b/src/tracing/core/service_impl.h
index 52b1277..8321b15 100644
--- a/src/tracing/core/service_impl.h
+++ b/src/tracing/core/service_impl.h
@@ -22,7 +22,7 @@
#include <memory>
#include <set>
-#include "perfetto/base/utils.h"
+#include "perfetto/base/page_allocator.h"
#include "perfetto/base/weak_ptr.h"
#include "perfetto/tracing/core/basic_types.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
@@ -151,6 +151,7 @@
TraceBuffer(TraceBuffer&&) noexcept;
TraceBuffer& operator=(TraceBuffer&&);
+ bool is_valid() const { return !!data; }
size_t num_pages() const { return size / kBufferPageSize; }
uint8_t* get_page(size_t page) {
@@ -166,7 +167,7 @@
size_t size;
size_t cur_page = 0; // Write pointer in the ring buffer.
- std::unique_ptr<void, base::FreeDeleter> data;
+ base::PageAllocator::UniquePtr data;
// TODO(primiano): The TraceBuffer is not shared and there is no reason to
// use the SharedMemoryABI. This is just a a temporary workaround to reuse
diff --git a/src/tracing/ipc/posix_shared_memory_unittest.cc b/src/tracing/ipc/posix_shared_memory_unittest.cc
index 5073f5a..c08e484 100644
--- a/src/tracing/ipc/posix_shared_memory_unittest.cc
+++ b/src/tracing/ipc/posix_shared_memory_unittest.cc
@@ -20,7 +20,6 @@
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
-#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -29,6 +28,7 @@
#include "perfetto/base/scoped_file.h"
#include "perfetto/base/utils.h"
#include "src/base/test/test_task_runner.h"
+#include "src/base/test/vm_test_utils.h"
namespace perfetto {
namespace {
@@ -39,29 +39,6 @@
return lseek(fd, 0, SEEK_CUR) == -1 && errno == EBADF;
}
-bool IsMapped(void* start, size_t size) {
-#if BUILDFLAG(OS_MACOSX)
- using PageState = char;
-#else
- using PageState = unsigned char;
-#endif
- EXPECT_EQ(0u, size % kPageSize);
- const size_t num_pages = size / kPageSize;
- std::unique_ptr<PageState[]> page_states(new PageState[num_pages]);
- memset(page_states.get(), 0, num_pages * sizeof(PageState));
- int res = mincore(start, size, page_states.get());
- // Linux returns ENOMEM when an unmapped memory range is passed.
- // MacOS instead returns 0 but leaves the page_states empty.
- if (res == -1 && errno == ENOMEM)
- return false;
- EXPECT_EQ(0, res);
- for (size_t i = 0; i < num_pages; i++) {
- if (!page_states[i])
- return false;
- }
- return true;
-}
-
TEST(PosixSharedMemoryTest, DestructorUnmapsMemory) {
PosixSharedMemory::Factory factory;
std::unique_ptr<SharedMemory> shm = factory.CreateSharedMemory(kPageSize);
@@ -71,10 +48,10 @@
ASSERT_EQ(kPageSize, shm_size);
memcpy(shm_start, "test", 5);
- ASSERT_TRUE(IsMapped(shm_start, shm_size));
+ ASSERT_TRUE(base::vm_test_utils::IsMapped(shm_start, shm_size));
shm.reset();
- ASSERT_FALSE(IsMapped(shm_start, shm_size));
+ ASSERT_FALSE(base::vm_test_utils::IsMapped(shm_start, shm_size));
}
TEST(PosixSharedMemoryTest, DestructorClosesFD) {
@@ -105,7 +82,7 @@
shm.reset();
ASSERT_TRUE(IsFileDescriptorClosed(fd_num));
- ASSERT_FALSE(IsMapped(shm_start, shm_size));
+ ASSERT_FALSE(base::vm_test_utils::IsMapped(shm_start, shm_size));
}
} // namespace
diff --git a/src/tracing/test/test_shared_memory.cc b/src/tracing/test/test_shared_memory.cc
index 6c1db1f..83ea281 100644
--- a/src/tracing/test/test_shared_memory.cc
+++ b/src/tracing/test/test_shared_memory.cc
@@ -24,11 +24,7 @@
namespace perfetto {
TestSharedMemory::TestSharedMemory(size_t size) {
- void* ptr = nullptr;
- int res = posix_memalign(&ptr, 4096, size);
- PERFETTO_CHECK(res == 0 && ptr);
- mem_.reset(ptr);
- memset(ptr, 0, size);
+ mem_ = base::PageAllocator::Allocate(size);
size_ = size;
}
diff --git a/src/tracing/test/test_shared_memory.h b/src/tracing/test/test_shared_memory.h
index e074e85..a4f44f8 100644
--- a/src/tracing/test/test_shared_memory.h
+++ b/src/tracing/test/test_shared_memory.h
@@ -21,7 +21,7 @@
#include <memory>
-#include "perfetto/base/utils.h"
+#include "perfetto/base/page_allocator.h"
#include "perfetto/tracing/core/shared_memory.h"
namespace perfetto {
@@ -42,7 +42,7 @@
void* start() const override { return mem_.get(); }
size_t size() const override { return size_; }
- std::unique_ptr<void, base::FreeDeleter> mem_;
+ base::PageAllocator::UniquePtr mem_;
size_t size_;
};