[libc-commits] [libc] cf0b9d3 - [libc] Add linux syscall wrappers for exit and exit_group (#230528)
via libc-commits
libc-commits at lists.llvm.org
Mon Oct 12 02:43:35 PDT 2026
Author: Pavel Labath
Date: 2026-10-12T11:43:30+02:00
New Revision: cf0b9d3d2e0a5bd54f4ac4fa89eed1d549f37688
URL: https://github.com/llvm/llvm-project/commit/cf0b9d3d2e0a5bd54f4ac4fa89eed1d549f37688
DIFF: https://github.com/llvm/llvm-project/commit/cf0b9d3d2e0a5bd54f4ac4fa89eed1d549f37688.diff
LOG: [libc] Add linux syscall wrappers for exit and exit_group (#230528)
Add dedicated linux syscall wrappers for SYS_exit and SYS_exit_group,
and update existing call sites to call the appropriate one instead of
using raw syscall_impl:
- exit_group terminates all threads in the thread group (process), so it
is used by internal::exit, posix_spawn child error exits, and do_start
initialization failure paths.
- exit terminates only the calling thread, so it is used in thread_exit
and tls init error paths.
Assisted-by: Gemini
Added:
libc/src/__support/OSUtil/linux/syscall_wrappers/exit.h
libc/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h
Modified:
libc/src/__support/OSUtil/linux/CMakeLists.txt
libc/src/__support/OSUtil/linux/exit.cpp
libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
libc/src/__support/threads/linux/CMakeLists.txt
libc/src/__support/threads/linux/aarch64/CMakeLists.txt
libc/src/__support/threads/linux/aarch64/tls.cpp
libc/src/__support/threads/linux/riscv/CMakeLists.txt
libc/src/__support/threads/linux/riscv/tls.cpp
libc/src/__support/threads/linux/thread.cpp
libc/src/__support/threads/linux/x86_64/CMakeLists.txt
libc/src/__support/threads/linux/x86_64/tls.cpp
libc/src/spawn/linux/CMakeLists.txt
libc/src/spawn/linux/posix_spawn.cpp
libc/startup/linux/CMakeLists.txt
libc/startup/linux/do_start.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 93f3d6d5190aa..e01f079c6780e 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -18,6 +18,7 @@ add_object_library(
libc.src.__support.common
libc.src.__support.CPP.string_view
libc.include.sys_syscall
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit_group
)
add_header_library(
diff --git a/libc/src/__support/OSUtil/linux/exit.cpp b/libc/src/__support/OSUtil/linux/exit.cpp
index e26b90f6b18eb..8e51d4d3c74d4 100644
--- a/libc/src/__support/OSUtil/linux/exit.cpp
+++ b/libc/src/__support/OSUtil/linux/exit.cpp
@@ -6,10 +6,9 @@
//
//===----------------------------------------------------------------------===//
-#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit_group.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
-#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
namespace internal {
@@ -21,10 +20,7 @@ __attribute__((no_stack_protector))
#endif
__attribute__((noreturn)) void
exit(int status) {
- for (;;) {
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit_group, status);
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, status);
- }
+ linux_syscalls::exit_group(status);
}
} // namespace internal
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 978a29a3384d0..b5404c9011f1d 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1633,3 +1633,23 @@ add_header_library(
libc.src.__support.error_or
libc.src.__support.macros.config
)
+
+add_header_library(
+ exit
+ HDRS
+ exit.h
+ DEPENDS
+ libc.include.sys_syscall
+ libc.src.__support.common
+ libc.src.__support.macros.config
+)
+
+add_header_library(
+ exit_group
+ HDRS
+ exit_group.h
+ DEPENDS
+ libc.include.sys_syscall
+ libc.src.__support.common
+ libc.src.__support.macros.config
+)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/exit.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/exit.h
new file mode 100644
index 0000000000000..a6df15b007e80
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/exit.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for exit.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+[[noreturn]] LIBC_INLINE void exit(int status) {
+ syscall_impl<long>(SYS_exit, status);
+ __builtin_trap();
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h
new file mode 100644
index 0000000000000..cf1a6fd086a25
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for exit_group.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_GROUP_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_GROUP_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+[[noreturn]] LIBC_INLINE void exit_group(int status) {
+ syscall_impl<long>(SYS_exit_group, status);
+ __builtin_trap();
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_GROUP_H
diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index d82b0c8e97918..145796c9bc7a5 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -76,6 +76,7 @@ add_object_library(
libc.src.__support.error_or
libc.src.__support.OSUtil.linux.syscall_wrappers.clone
libc.src.__support.OSUtil.linux.syscall_wrappers.close
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit
libc.src.__support.OSUtil.linux.syscall_wrappers.getpid
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.mprotect
diff --git a/libc/src/__support/threads/linux/aarch64/CMakeLists.txt b/libc/src/__support/threads/linux/aarch64/CMakeLists.txt
index b83ccbb1ee05f..e6e92d814cc0a 100644
--- a/libc/src/__support/threads/linux/aarch64/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/aarch64/CMakeLists.txt
@@ -7,6 +7,7 @@ add_object_library(
libc.hdr.sys_mman_macros
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
libc.src.__support.threads.linux.tcb
diff --git a/libc/src/__support/threads/linux/aarch64/tls.cpp b/libc/src/__support/threads/linux/aarch64/tls.cpp
index fef46c109fa33..bf922aaf0b2cf 100644
--- a/libc/src/__support/threads/linux/aarch64/tls.cpp
+++ b/libc/src/__support/threads/linux/aarch64/tls.cpp
@@ -8,6 +8,7 @@
#include "config/app.h"
#include "hdr/sys_mman_macros.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/OSUtil/syscall.h"
@@ -46,7 +47,7 @@ namespace LIBC_NAMESPACE_DECL {
linux_syscalls::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!mmap_ret.has_value())
- syscall_impl<long>(SYS_exit, 1);
+ linux_syscalls::exit(1);
uintptr_t thread_ptr = uintptr_t(mmap_ret.value());
uintptr_t tls_addr = thread_ptr + TCB_SIZE + padding;
inline_memcpy(reinterpret_cast<char *>(tls_addr),
diff --git a/libc/src/__support/threads/linux/riscv/CMakeLists.txt b/libc/src/__support/threads/linux/riscv/CMakeLists.txt
index b83ccbb1ee05f..e6e92d814cc0a 100644
--- a/libc/src/__support/threads/linux/riscv/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/riscv/CMakeLists.txt
@@ -7,6 +7,7 @@ add_object_library(
libc.hdr.sys_mman_macros
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
libc.src.__support.threads.linux.tcb
diff --git a/libc/src/__support/threads/linux/riscv/tls.cpp b/libc/src/__support/threads/linux/riscv/tls.cpp
index 5bd338dbd991d..88a45a09df104 100644
--- a/libc/src/__support/threads/linux/riscv/tls.cpp
+++ b/libc/src/__support/threads/linux/riscv/tls.cpp
@@ -8,6 +8,7 @@
#include "config/app.h"
#include "hdr/sys_mman_macros.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/OSUtil/syscall.h"
@@ -33,7 +34,7 @@ namespace LIBC_NAMESPACE_DECL {
linux_syscalls::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!mmap_ret.has_value())
- syscall_impl<long>(SYS_exit, 1);
+ linux_syscalls::exit(1);
uintptr_t thread_ptr = uintptr_t(mmap_ret.value());
uintptr_t tls_addr = thread_ptr + TCB_SIZE + padding;
inline_memcpy(reinterpret_cast<char *>(tls_addr),
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index 948a8582ca254..a67f7355a12d3 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -18,6 +18,7 @@
#include "src/__support/CPP/stringstream.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/clone.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/getpid.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/mprotect.h"
@@ -512,15 +513,14 @@ void thread_exit(ThreadReturnValue retval, ThreadStyle style) {
// Return value for detached thread should be unused. We need to avoid
// referencing `style` or `retval.*` because they may be stored on the stack
// and we have deallocated our stack!
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 0);
- __builtin_unreachable();
+ linux_syscalls::exit(0);
}
if (style == ThreadStyle::POSIX)
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, retval.posix_retval);
+ linux_syscalls::exit(
+ static_cast<int>(reinterpret_cast<uintptr_t>(retval.posix_retval)));
else
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, retval.stdc_retval);
- __builtin_unreachable();
+ linux_syscalls::exit(retval.stdc_retval);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/linux/x86_64/CMakeLists.txt b/libc/src/__support/threads/linux/x86_64/CMakeLists.txt
index e827fb2d7e9c0..0b49ca2c7e6e3 100644
--- a/libc/src/__support/threads/linux/x86_64/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/x86_64/CMakeLists.txt
@@ -7,6 +7,7 @@ add_object_library(
libc.hdr.sys_mman_macros
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit
libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
diff --git a/libc/src/__support/threads/linux/x86_64/tls.cpp b/libc/src/__support/threads/linux/x86_64/tls.cpp
index 82462e3975ae0..af2e16740681b 100644
--- a/libc/src/__support/threads/linux/x86_64/tls.cpp
+++ b/libc/src/__support/threads/linux/x86_64/tls.cpp
@@ -8,6 +8,7 @@
#include "config/app.h"
#include "hdr/sys_mman_macros.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
@@ -33,7 +34,7 @@ namespace LIBC_NAMESPACE_DECL {
linux_syscalls::mmap(nullptr, tls_size_with_tcb, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!mmap_ret.has_value())
- syscall_impl<long>(SYS_exit, 1);
+ linux_syscalls::exit(1);
uintptr_t *tls_addr = static_cast<uintptr_t *>(mmap_ret.value());
// x86_64 TLS faces down from the thread pointer with the first entry
@@ -55,7 +56,7 @@ namespace LIBC_NAMESPACE_DECL {
ErrorOr<ssize_t> stack_guard_retval =
linux_syscalls::getrandom(&tcb->stack_guard, sizeof(tcb->stack_guard), 0);
if (!stack_guard_retval.has_value())
- syscall_impl(SYS_exit, 1);
+ linux_syscalls::exit(1);
tls_descriptor = {tls_size_with_tcb, reinterpret_cast<uintptr_t>(tls_addr),
end_ptr};
diff --git a/libc/src/spawn/linux/CMakeLists.txt b/libc/src/spawn/linux/CMakeLists.txt
index 2293f8db9bf0a..a72424f6e1cc7 100644
--- a/libc/src/spawn/linux/CMakeLists.txt
+++ b/libc/src/spawn/linux/CMakeLists.txt
@@ -13,6 +13,7 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
libc.src.__support.OSUtil.linux.syscall_wrappers.close
libc.src.__support.OSUtil.linux.syscall_wrappers.dup2
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit_group
libc.src.__support.OSUtil.linux.syscall_wrappers.open
libc.src.spawn.file_actions
libc.src.signal.linux.signal_utils
diff --git a/libc/src/spawn/linux/posix_spawn.cpp b/libc/src/spawn/linux/posix_spawn.cpp
index 00bfc8785c67b..3c2323ccbe68b 100644
--- a/libc/src/spawn/linux/posix_spawn.cpp
+++ b/libc/src/spawn/linux/posix_spawn.cpp
@@ -9,6 +9,7 @@
#include "src/spawn/posix_spawn.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/dup2.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit_group.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
@@ -43,12 +44,7 @@ pid_t fork() {
// All exits from child_process are error exits. So, we use a simple
// exit implementation which exits with code 127.
-void exit() {
- for (;;) {
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit_group, 127);
- LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 127);
- }
-}
+[[noreturn]] void exit() { linux_syscalls::exit_group(127); }
void child_process(const char *__restrict path,
const posix_spawn_file_actions_t *file_actions,
diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index 04647dc4c612c..18379a9b4e448 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -120,6 +120,7 @@ add_object_library(
libc.hdr.types.struct_r_debug
libc.include.sys_syscall
libc.src.__support.OSUtil.linux.auxv
+ libc.src.__support.OSUtil.linux.syscall_wrappers.exit_group
libc.src.__support.OSUtil.osutil
libc.src.__support.threads.tcb
libc.src.__support.threads.thread
diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index 54b5dbebaafd4..504411971f43f 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -16,6 +16,7 @@
#include "hdr/types/struct_link_map.h"
#include "hdr/types/struct_r_debug.h"
#include "src/__support/OSUtil/linux/auxv.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/exit_group.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/linux/futex_utils.h"
@@ -83,7 +84,7 @@ static TLSDescriptor tls;
[[noreturn]] void do_start() {
auto tid = syscall_impl<long>(SYS_gettid);
if (tid <= 0)
- syscall_impl<long>(SYS_exit, 1);
+ linux_syscalls::exit_group(1);
main_thread_attrib.tid = static_cast<int>(tid);
main_thread_attrib.platform_data = &main_thread_clear_tid;
main_thread_attrib.detach_state =
@@ -202,7 +203,7 @@ static TLSDescriptor tls;
// capture the context.
init_tls(tls);
if (!set_thread_ptr(tls.tp))
- syscall_impl<long>(SYS_exit, 1);
+ linux_syscalls::exit_group(1);
get_tcb(tls.tp)->attrib = &main_thread_attrib;
More information about the libc-commits
mailing list