blob: e15b904c86dcf8efc8e3f2b9d00bbf827f60cc5b [file] [log] [blame] [edit]
// 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