[libc] (reland #117503) Implement process_mrelease (#117851)

This PR implements process_mrelease.
A previous PR was merged #117503, but failed on merge due to an issue in
the tests. Namely the failing tests were comparing against return type
as opposed to errno. This is fixed in this PR.

GitOrigin-RevId: d2b482b0efd1d523852c9add8ed6b2035ce1acd9
diff --git a/config/linux/aarch64/entrypoints.txt b/config/linux/aarch64/entrypoints.txt
index 74ca374..08b5072 100644
--- a/config/linux/aarch64/entrypoints.txt
+++ b/config/linux/aarch64/entrypoints.txt
@@ -252,6 +252,7 @@
     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/config/linux/riscv/entrypoints.txt b/config/linux/riscv/entrypoints.txt
index 5419462..4ea65f7 100644
--- a/config/linux/riscv/entrypoints.txt
+++ b/config/linux/riscv/entrypoints.txt
@@ -251,6 +251,7 @@
     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/config/linux/x86_64/entrypoints.txt b/config/linux/x86_64/entrypoints.txt
index 957e28b..d0651c0 100644
--- a/config/linux/x86_64/entrypoints.txt
+++ b/config/linux/x86_64/entrypoints.txt
@@ -252,6 +252,7 @@
     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/include/sys/syscall.h.def b/include/sys/syscall.h.def
index 03c19eb..11758ea 100644
--- a/include/sys/syscall.h.def
+++ b/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/newhdrgen/yaml/sys/mman.yaml b/newhdrgen/yaml/sys/mman.yaml
index 962ca35..dd53eb6 100644
--- a/newhdrgen/yaml/sys/mman.yaml
+++ b/newhdrgen/yaml/sys/mman.yaml
@@ -132,3 +132,10 @@
     return_type: int
     arguments:
       - type: const char *
+  - name: process_mrelease
+    standards:
+      - Linux
+    return_type: int
+    arguments:
+      - type: int
+      - type: unsigned int
diff --git a/spec/linux.td b/spec/linux.td
index 9b5dc8e..99e0949 100644
--- a/spec/linux.td
+++ b/spec/linux.td
@@ -112,6 +112,12 @@
             ArgSpec<IntType>,
             ArgSpec<SizeTType>,
             ArgSpec<IntType>,
+        FunctionSpec<
+          "process_mrelease",
+          RetValSpec<IntType>,
+          [
+            ArgSpec<IntType>,
+            ArgSpec<UnsignedIntType>
           ]
         >,
         FunctionSpec<
diff --git a/src/sys/mman/CMakeLists.txt b/src/sys/mman/CMakeLists.txt
index 4d4c2ad..281efc0 100644
--- a/src/sys/mman/CMakeLists.txt
+++ b/src/sys/mman/CMakeLists.txt
@@ -113,3 +113,9 @@
   DEPENDS
     .${LIBC_TARGET_OS}.mremap
 )
+
+add_entrypoint_object(
+  process_mrelease 
+  ALIAS 
+  DEPENDS
+    .${LIBC_TARGET_OS}.process_mrelease)
diff --git a/src/sys/mman/linux/CMakeLists.txt b/src/sys/mman/linux/CMakeLists.txt
index 89a0ad1..aa2ca4b 100644
--- a/src/sys/mman/linux/CMakeLists.txt
+++ b/src/sys/mman/linux/CMakeLists.txt
@@ -36,7 +36,6 @@
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
-
 add_entrypoint_object(
   munmap
   SRCS
@@ -214,3 +213,14 @@
     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/src/sys/mman/linux/process_mrelease.cpp b/src/sys/mman/linux/process_mrelease.cpp
new file mode 100644
index 0000000..e86bbec
--- /dev/null
+++ b/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 <linux/param.h> // For EXEC_PAGESIZE.
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, process_mrelease, (int pidfd, unsigned int flags)) {
+  long ret =
+      LIBC_NAMESPACE::syscall_impl<int>(SYS_process_mrelease, pidfd, flags);
+
+  if (ret < 0) {
+    libc_errno = static_cast<int>(-ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/src/sys/mman/process_mrelease.h b/src/sys/mman/process_mrelease.h
new file mode 100644
index 0000000..6c800f2
--- /dev/null
+++ b/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 <sys/mman.h> // 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/test/src/sys/mman/linux/CMakeLists.txt b/test/src/sys/mman/linux/CMakeLists.txt
index 44ed11a..1a5ff3a 100644
--- a/test/src/sys/mman/linux/CMakeLists.txt
+++ b/test/src/sys/mman/linux/CMakeLists.txt
@@ -181,3 +181,23 @@
     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
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/test/src/sys/mman/linux/process_mrelease_test.cpp b/test/src/sys/mman/linux/process_mrelease_test.cpp
new file mode 100644
index 0000000..56a7d66
--- /dev/null
+++ b/test/src/sys/mman/linux/process_mrelease_test.cpp
@@ -0,0 +1,74 @@
+//===-- 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/ErrnoSetterMatcher.h"
+#include "test/UnitTest/LibcTest.h"
+
+#include <sys/syscall.h>
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+
+int pidfd_open(pid_t pid, unsigned int flags) {
+  return LIBC_NAMESPACE::syscall_impl(SYS_pidfd_open, pid, flags);
+}
+
+TEST(LlvmLibcProcessMReleaseTest, 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_THAT(LIBC_NAMESPACE::process_mrelease(pidfd, 0), Succeeds());
+
+    LIBC_NAMESPACE::close(pidfd);
+  }
+}
+
+TEST(LlvmLibcProcessMReleaseTest, 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);
+
+    EXPECT_THAT(LIBC_NAMESPACE::process_mrelease(pidfd, 0), Fails(EINVAL));
+
+    LIBC_NAMESPACE::close(pidfd);
+  }
+}
+
+TEST(LlvmLibcProcessMReleaseTest, ErrorNonExistingPidfd) {
+  EXPECT_THAT(LIBC_NAMESPACE::process_mrelease(-1, 0), Fails(EBADF));
+}