diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 74ca3742977a5..08b5072499da6 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -252,6 +252,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.mman.munlockall libc.src.sys.mman.munmap libc.src.sys.mman.remap_file_pages + libc.src.sys.mman.process_mrelease libc.src.sys.mman.posix_madvise libc.src.sys.mman.shm_open libc.src.sys.mman.shm_unlink diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 5419462d4f5b3..4ea65f76d7948 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -251,6 +251,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.mman.munmap libc.src.sys.mman.remap_file_pages libc.src.sys.mman.posix_madvise + libc.src.sys.mman.process_mrelease libc.src.sys.mman.shm_open libc.src.sys.mman.shm_unlink diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 957e28bd66cc4..d0651c06b930a 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -252,6 +252,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.mman.munmap libc.src.sys.mman.remap_file_pages libc.src.sys.mman.posix_madvise + libc.src.sys.mman.process_mrelease libc.src.sys.mman.shm_open libc.src.sys.mman.shm_unlink diff --git a/libc/include/sys/syscall.h.def b/libc/include/sys/syscall.h.def index 03c19eb0885ed..11758ea8336dd 100644 --- a/libc/include/sys/syscall.h.def +++ b/libc/include/sys/syscall.h.def @@ -2349,5 +2349,12 @@ #define SYS_writev __NR_writev #endif +#ifdef __NR_process_mrelease +#define SYS_process_mrelease __NR_process_mrelease +#endif + +#ifdef __NR_pidfd_open +#define SYS_pidfd_open __NR_pidfd_open +#endif #endif // LLVM_LIBC_SYS_SYSCALL_H diff --git a/libc/newhdrgen/yaml/sys/mman.yaml b/libc/newhdrgen/yaml/sys/mman.yaml index 962ca3591917f..dd53eb60d1ec5 100644 --- a/libc/newhdrgen/yaml/sys/mman.yaml +++ b/libc/newhdrgen/yaml/sys/mman.yaml @@ -132,3 +132,10 @@ functions: return_type: int arguments: - type: const char * + - name: process_mrelease + standards: + - Linux + return_type: int + arguments: + - type: int + - type: unsigned int diff --git a/libc/spec/linux.td b/libc/spec/linux.td index 9b5dc8e30c95e..99e0949a592df 100644 --- a/libc/spec/linux.td +++ b/libc/spec/linux.td @@ -112,6 +112,12 @@ def Linux : StandardSpec<"Linux"> { ArgSpec, ArgSpec, ArgSpec, + FunctionSpec< + "process_mrelease", + RetValSpec, + [ + ArgSpec, + ArgSpec ] >, FunctionSpec< diff --git a/libc/src/sys/mman/CMakeLists.txt b/libc/src/sys/mman/CMakeLists.txt index 4d4c2ad376050..281efc0ffcdf2 100644 --- a/libc/src/sys/mman/CMakeLists.txt +++ b/libc/src/sys/mman/CMakeLists.txt @@ -113,3 +113,9 @@ add_entrypoint_object( DEPENDS .${LIBC_TARGET_OS}.mremap ) + +add_entrypoint_object( + process_mrelease + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.process_mrelease) diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt index 89a0ad1527a06..aa2ca4b160181 100644 --- a/libc/src/sys/mman/linux/CMakeLists.txt +++ b/libc/src/sys/mman/linux/CMakeLists.txt @@ -36,7 +36,6 @@ add_entrypoint_object( libc.src.__support.OSUtil.osutil libc.src.errno.errno ) - add_entrypoint_object( munmap SRCS @@ -214,3 +213,14 @@ add_entrypoint_object( libc.src.unistd.unlink .shm_common ) + +add_entrypoint_object( + process_mrelease + SRCS + process_mrelease.cpp + HDRS + ../process_mrelease.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno) diff --git a/libc/src/sys/mman/linux/process_mrelease.cpp b/libc/src/sys/mman/linux/process_mrelease.cpp new file mode 100644 index 0000000000000..e86bbec1b1b66 --- /dev/null +++ b/libc/src/sys/mman/linux/process_mrelease.cpp @@ -0,0 +1,33 @@ +//===---------- Linux implementation of the mrelease function -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/sys/mman/process_mrelease.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include "src/__support/macros/config.h" +#include "src/errno/libc_errno.h" +#include // For EXEC_PAGESIZE. +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, process_mrelease, (int pidfd, unsigned int flags)) { + long ret = + LIBC_NAMESPACE::syscall_impl(SYS_process_mrelease, pidfd, flags); + + if (ret < 0) { + libc_errno = static_cast(-ret); + return -1; + } + + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/process_mrelease.h b/libc/src/sys/mman/process_mrelease.h new file mode 100644 index 0000000000000..ec4a6e4768bca --- /dev/null +++ b/libc/src/sys/mman/process_mrelease.h @@ -0,0 +1,21 @@ +//===-- Implementation header for process_mrelease function --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===-------------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_MMAN_PROCESS_MRELEASE_H +#define LLVM_LIBC_SRC_SYS_MMAN_PROCESS_MRELEASE_H + +#include "src/__support/macros/config.h" +#include // For size_t and off_t + +namespace LIBC_NAMESPACE_DECL { + +int process_mrelease(int pidfd, unsigned int flags); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_PROCESS_MRELEASE_H diff --git a/libc/test/src/sys/mman/linux/CMakeLists.txt b/libc/test/src/sys/mman/linux/CMakeLists.txt index 44ed11aadfe8b..35dcf832729be 100644 --- a/libc/test/src/sys/mman/linux/CMakeLists.txt +++ b/libc/test/src/sys/mman/linux/CMakeLists.txt @@ -181,3 +181,21 @@ add_libc_unittest( libc.hdr.fcntl_macros libc.test.UnitTest.ErrnoSetterMatcher ) + +add_libc_unittest( + process_mrelease_test + SUITE + libc_sys_mman_unittests + SRCS + process_mrelease_test.cpp + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.errno.errno + libc.src.sys.mman.process_mrelease + libc.src.unistd.close + libc.src.signal.kill + libc.include.signal + libc.src.stdlib.exit + libc.src.__support.OSUtil.osutil + libc.src.__support.threads.sleep) diff --git a/libc/test/src/sys/mman/linux/process_mrelease_test.cpp b/libc/test/src/sys/mman/linux/process_mrelease_test.cpp new file mode 100644 index 0000000000000..3349a5ee0a548 --- /dev/null +++ b/libc/test/src/sys/mman/linux/process_mrelease_test.cpp @@ -0,0 +1,72 @@ +//===-- Unittests for process_mrelease ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/threads/sleep.h" +#include "src/errno/libc_errno.h" +#include "src/signal/kill.h" +#include "src/stdlib/exit.h" +#include "src/sys/mman/process_mrelease.h" +#include "src/unistd/close.h" +#include "src/unistd/fork.h" +#include "test/UnitTest/LibcTest.h" + +#include + +int pidfd_open(pid_t pid, unsigned int flags) { + return LIBC_NAMESPACE::syscall_impl(SYS_pidfd_open, pid, flags); +} + +TEST(LlvmLibcMProcessMReleaseTest, NoError) { + pid_t child_pid = fork(); + EXPECT_GE(child_pid, 0); + + if (child_pid == 0) { + // Child process: wait a bit then exit gracefully. + LIBC_NAMESPACE::sleep_briefly(); + LIBC_NAMESPACE::exit(0); + } else { + // Parent process: wait a bit and then kill the child. + // Give child process some time to start. + LIBC_NAMESPACE::sleep_briefly(); + int pidfd = pidfd_open(child_pid, 0); + EXPECT_GE(pidfd, 0); + + // Send SIGKILL to child process + LIBC_NAMESPACE::kill(child_pid, SIGKILL); + + EXPECT_EQ(LIBC_NAMESPACE::process_mrelease(pidfd, 0), 0); + + LIBC_NAMESPACE::close(pidfd); + } +} + +TEST(LlvmLibcMProcessMReleaseTest, ErrorNotKilled) { + pid_t child_pid = fork(); + EXPECT_GE(child_pid, 0); + + if (child_pid == 0) { + // Child process: wait a bit then exit gracefully. + LIBC_NAMESPACE::sleep_briefly(); + LIBC_NAMESPACE::exit(0); + } else { + // Give child process some time to start. + LIBC_NAMESPACE::sleep_briefly(); + int pidfd = pidfd_open(child_pid, 0); + EXPECT_GE(pidfd, 0); + + ASSERT_EQ(LIBC_NAMESPACE::process_mrelease(pidfd, 0), EINVAL); + + LIBC_NAMESPACE::close(pidfd); + } +} + +TEST(LlvmLibcMProcessMReleaseTest, ErrorNonExistingPidfd) { + + ASSERT_EQ(LIBC_NAMESPACE::process_mrelease(-1, 0), EBADF); +}