| // Copyright 2026 The Fuchsia 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 <lib/syslog/cpp/macros.h> |
| #include <sys/mman.h> |
| #include <sys/syscall.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <unistd.h> |
| |
| #include <vector> |
| |
| #include <fbl/string_printf.h> |
| #include <perftest/perftest.h> |
| |
| #include "scoped_mapping.h" |
| #include "simple_latch.h" |
| |
| #ifndef MFD_CLOEXEC |
| #define MFD_CLOEXEC 0x0001U |
| #endif |
| |
| namespace { |
| |
| void WaitForChild(pid_t pid) { |
| int status; |
| pid_t child_pid = waitpid(pid, &status, 0); |
| FX_CHECK(child_pid == pid); |
| FX_CHECK(WIFEXITED(status)); |
| FX_CHECK(WEXITSTATUS(status) == 0); |
| } |
| |
| class Sync { |
| public: |
| SimpleLatch pending_children; |
| SimpleLatch parent_done; |
| |
| Sync() : pending_children(1), parent_done(1) {} |
| }; |
| |
| bool CloneWithMappings(perftest::RepeatState* state, int count) { |
| std::vector<void*> mappings; |
| mappings.reserve(count * 2); |
| |
| int fd = static_cast<int>(syscall(SYS_memfd_create, "test", MFD_CLOEXEC)); |
| FX_CHECK(fd >= 0); |
| FX_CHECK(ftruncate(fd, 4096) == 0); |
| |
| for (int i = 0; i < count; i++) { |
| void* p1 = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| FX_CHECK(p1 != MAP_FAILED); |
| mappings.push_back(p1); |
| |
| void* p2 = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); |
| FX_CHECK(p2 != MAP_FAILED); |
| mappings.push_back(p2); |
| } |
| |
| ScopedMapping mapping(sizeof(Sync), PROT_READ | PROT_WRITE, |
| MAP_SHARED | MAP_ANONYMOUS | MAP_POPULATE); |
| |
| state->DeclareStep("sys_clone"); |
| state->DeclareStep("wait"); |
| |
| while (state->KeepRunning()) { |
| Sync* sync = new (reinterpret_cast<void*>(mapping.base())) Sync(); |
| |
| // clone without CLONE_THREAD |
| pid_t pid = static_cast<pid_t>(syscall(SYS_clone, SIGCHLD, 0, 0, 0, 0)); |
| FX_CHECK(pid >= 0); |
| |
| if (pid == 0) { |
| sync->pending_children.CountDown(); |
| sync->parent_done.Wait(); |
| _exit(EXIT_SUCCESS); |
| } |
| |
| sync->pending_children.Wait(); |
| |
| state->NextStep(); |
| sync->parent_done.CountDown(); |
| |
| WaitForChild(pid); |
| sync->~Sync(); |
| } |
| |
| for (void* p : mappings) { |
| FX_CHECK(munmap(p, 4096) == 0); |
| } |
| FX_CHECK(close(fd) == 0); |
| |
| return true; |
| } |
| |
| void RegisterTests() { |
| for (int count : {128, 1024, 4096}) { |
| auto test_name = fbl::StringPrintf("CloneWithMappings/%d", count); |
| perftest::RegisterTest(test_name.c_str(), CloneWithMappings, count); |
| } |
| } |
| PERFTEST_CTOR(RegisterTests) |
| |
| } // namespace |