[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