[libc-commits] [libc] [libc] Implement accept4 on linux (PR #192927)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Mon Apr 20 07:29:46 PDT 2026


https://github.com/labath updated https://github.com/llvm/llvm-project/pull/192927

>From 88988f992493e722589fb6d8d912d88ba43abe98 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 20 Apr 2026 09:53:05 +0000
Subject: [PATCH 1/3] [libc] Implement accept4(2) on linux

Testing funcitonality by checking the flags on the returned FD.
---
 libc/config/linux/aarch64/entrypoints.txt     |  1 +
 libc/config/linux/riscv/entrypoints.txt       |  1 +
 libc/config/linux/x86_64/entrypoints.txt      |  1 +
 .../linux/sys-socket-macros.h                 |  3 ++
 libc/include/sys/socket.yaml                  |  9 ++++
 .../linux/syscall_wrappers/CMakeLists.txt     | 14 +++++
 libc/src/sys/socket/CMakeLists.txt            |  7 +++
 libc/src/sys/socket/linux/CMakeLists.txt      | 14 +++++
 libc/test/src/sys/socket/linux/CMakeLists.txt |  3 ++
 .../sys/socket/linux/connect_accept_test.cpp  | 53 +++++++++++++++++++
 10 files changed, 106 insertions(+)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 87bd5461496b3..15d7c799883c0 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1214,6 +1214,7 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # sys/socket.h entrypoints
     libc.src.sys.socket.accept
+    libc.src.sys.socket.accept4
     libc.src.sys.socket.bind
     libc.src.sys.socket.connect
     libc.src.sys.socket.getsockopt
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index ea117c1d83c24..554641d4fc5d4 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1348,6 +1348,7 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # sys/socket.h entrypoints
     libc.src.sys.socket.accept
+    libc.src.sys.socket.accept4
     libc.src.sys.socket.bind
     libc.src.sys.socket.connect
     libc.src.sys.socket.getsockopt
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5c69c8808b2c1..5ce78e755a110 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1422,6 +1422,7 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # sys/socket.h entrypoints
     libc.src.sys.socket.accept
+    libc.src.sys.socket.accept4
     libc.src.sys.socket.socket
     libc.src.sys.socket.bind
     libc.src.sys.socket.connect
diff --git a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
index 5a5cfd578dcbf..b7c52b9b0c349 100644
--- a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
@@ -25,6 +25,9 @@
 #define SOCK_SEQPACKET 5
 #define SOCK_PACKET 10
 
+#define SOCK_CLOEXEC 0x80000
+#define SOCK_NONBLOCK 0x800
+
 #define SOL_SOCKET 1
 
 #define SO_DEBUG 1
diff --git a/libc/include/sys/socket.yaml b/libc/include/sys/socket.yaml
index 28a81328a3559..e6b93827e3646 100644
--- a/libc/include/sys/socket.yaml
+++ b/libc/include/sys/socket.yaml
@@ -24,6 +24,15 @@ functions:
       - type: int
       - type: struct sockaddr *__restrict
       - type: socklen_t *__restrict
+  - name: accept4
+    standards:
+      - Linux
+    return_type: int
+    arguments:
+      - type: int
+      - type: struct sockaddr *__restrict
+      - type: socklen_t *__restrict
+      - type: int
   - name: bind
     standards:
       - POSIX
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index f00fa9668afe7..049eeac913780 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -38,6 +38,20 @@ add_header_library(
     libc.include.sys_syscall
 )
 
+add_header_library(
+  accept4
+  HDRS
+    accept4.h
+  DEPENDS
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.config
+    libc.hdr.types.socklen_t
+    libc.hdr.types.struct_sockaddr
+    libc.include.sys_syscall
+)
+
 add_header_library(
   connect
   HDRS
diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt
index 50558c667c78a..70be4c048d90f 100644
--- a/libc/src/sys/socket/CMakeLists.txt
+++ b/libc/src/sys/socket/CMakeLists.txt
@@ -16,6 +16,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.accept
 )
 
+add_entrypoint_object(
+  accept4
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.accept4
+)
+
 add_entrypoint_object(
   bind
   ALIAS
diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt
index c63a8e1fafe19..417a00e552f82 100644
--- a/libc/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/src/sys/socket/linux/CMakeLists.txt
@@ -38,6 +38,20 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  accept4
+  SRCS
+    accept4.cpp
+  HDRS
+    ../accept4.h
+  DEPENDS
+    libc.include.sys_socket
+    libc.src.__support.OSUtil.osutil
+    libc.hdr.types.struct_sockaddr
+    libc.hdr.types.socklen_t
+    libc.src.errno.errno
+)
+
 add_entrypoint_object(
   connect
   SRCS
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index af0a46e9a06bb..10ca9039f5b9d 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -42,11 +42,14 @@ add_libc_unittest(
     connect_accept_test.cpp
   DEPENDS
     libc.include.sys_socket
+    libc.hdr.fcntl_macros
     libc.hdr.sys_socket_macros
     libc.hdr.types.size_t
     libc.hdr.types.struct_sockaddr_un
     libc.src.errno.errno
+    libc.src.fcntl.fcntl
     libc.src.sys.socket.accept
+    libc.src.sys.socket.accept4
     libc.src.sys.socket.bind
     libc.src.sys.socket.connect
     libc.src.sys.socket.listen
diff --git a/libc/test/src/sys/socket/linux/connect_accept_test.cpp b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
index b95992d030324..c523d470f616f 100644
--- a/libc/test/src/sys/socket/linux/connect_accept_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
@@ -6,10 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/fcntl_macros.h"
 #include "hdr/sys_socket_macros.h"
 #include "hdr/types/size_t.h"
 #include "hdr/types/struct_sockaddr_un.h"
+#include "src/fcntl/fcntl.h"
 #include "src/sys/socket/accept.h"
+#include "src/sys/socket/accept4.h"
 #include "src/sys/socket/bind.h"
 #include "src/sys/socket/connect.h"
 #include "src/sys/socket/listen.h"
@@ -123,3 +126,53 @@ TEST_F(LlvmLibcConnectAcceptTest, ConnectLocalSocket) {
   ASSERT_THAT(LIBC_NAMESPACE::remove(ACCEPT_PATH), Succeeds(0));
   ASSERT_THAT(LIBC_NAMESPACE::remove(CONNECT_PATH), Succeeds(0));
 }
+
+TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
+  const char *ACCEPT_FILE = "accept4_file.test";
+  auto ACCEPT_PATH = libc_make_test_file_path(ACCEPT_FILE);
+  ASSERT_LT(LIBC_NAMESPACE::strlen(ACCEPT_PATH), MAX_SOCKET_PATH);
+  const struct sockaddr_un ACCEPT_ADDR = make_sockaddr(ACCEPT_PATH);
+
+  int accepting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+  ASSERT_GE(accepting_socket, 0);
+  ASSERT_ERRNO_SUCCESS();
+
+  ASSERT_THAT(LIBC_NAMESPACE::bind(
+                  accepting_socket,
+                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  sizeof(struct sockaddr_un)),
+              Succeeds(0));
+
+  ASSERT_THAT(LIBC_NAMESPACE::listen(accepting_socket, 1), Succeeds(0));
+
+  int connecting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+  ASSERT_GE(connecting_socket, 0);
+  ASSERT_ERRNO_SUCCESS();
+
+  ASSERT_THAT(LIBC_NAMESPACE::connect(
+                  connecting_socket,
+                  reinterpret_cast<const struct sockaddr *>(&ACCEPT_ADDR),
+                  sizeof(struct sockaddr_un)),
+              Succeeds(0));
+
+  int accepted_socket = LIBC_NAMESPACE::accept4(
+      accepting_socket, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
+  ASSERT_GE(accepted_socket, 0);
+  ASSERT_ERRNO_SUCCESS();
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(connecting_socket), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(accepting_socket), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::remove(ACCEPT_PATH), Succeeds(0));
+
+  // Check FD_CLOEXEC
+  int fd_flags = LIBC_NAMESPACE::fcntl(accepted_socket, F_GETFD);
+  ASSERT_GE(fd_flags, 0);
+  ASSERT_NE(fd_flags & FD_CLOEXEC, 0);
+
+  // Check O_NONBLOCK
+  int fl_flags = LIBC_NAMESPACE::fcntl(accepted_socket, F_GETFL);
+  ASSERT_GE(fl_flags, 0);
+  ASSERT_NE(fl_flags & O_NONBLOCK, 0);
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(accepted_socket), Succeeds(0));
+}

>From 8938a0135626555c1f1b4974d234f87e7f2c664e Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 20 Apr 2026 10:04:59 +0000
Subject: [PATCH 2/3] add missing files

---
 .../OSUtil/linux/syscall_wrappers/accept4.h   | 49 +++++++++++++++++++
 libc/src/sys/socket/accept4.h                 | 24 +++++++++
 libc/src/sys/socket/linux/accept4.cpp         | 31 ++++++++++++
 3 files changed, 104 insertions(+)
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/accept4.h
 create mode 100644 libc/src/sys/socket/accept4.h
 create mode 100644 libc/src/sys/socket/linux/accept4.cpp

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/accept4.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/accept4.h
new file mode 100644
index 0000000000000..ebe82f189af50
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/accept4.h
@@ -0,0 +1,49 @@
+//===-- Implementation header for accept4 -----------------------*- 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___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ACCEPT4_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ACCEPT4_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr.h"
+#include <linux/net.h>   // For SYS_ACCEPT4 socketcall number.
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> accept4(int sockfd, struct sockaddr *addr,
+                                 socklen_t *addrlen, int flags) {
+#ifdef SYS_accept4
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_accept4, sockfd, addr,
+                                              addrlen, flags);
+#elif defined(SYS_socketcall)
+  unsigned long sockcall_args[4] = {static_cast<unsigned long>(sockfd),
+                                    reinterpret_cast<unsigned long>(addr),
+                                    reinterpret_cast<unsigned long>(addrlen),
+                                    static_cast<unsigned long>(flags)};
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_socketcall, SYS_ACCEPT4,
+                                              sockcall_args);
+#else
+#error "accept4 and socketcall syscalls unavailable for this platform."
+#endif
+
+  if (ret < 0)
+    return Error(-static_cast<int>(ret));
+  return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ACCEPT4_H
diff --git a/libc/src/sys/socket/accept4.h b/libc/src/sys/socket/accept4.h
new file mode 100644
index 0000000000000..d5d14b684bb2e
--- /dev/null
+++ b/libc/src/sys/socket/accept4.h
@@ -0,0 +1,24 @@
+//===-- Implementation header for accept4 -----------------------*- 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_SOCKET_ACCEPT4_H
+#define LLVM_LIBC_SRC_SYS_SOCKET_ACCEPT4_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int accept4(int sockfd, struct sockaddr *__restrict addr,
+            socklen_t *__restrict addrlen, int flags);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SOCKET_ACCEPT4_H
diff --git a/libc/src/sys/socket/linux/accept4.cpp b/libc/src/sys/socket/linux/accept4.cpp
new file mode 100644
index 0000000000000..bfe36c547072f
--- /dev/null
+++ b/libc/src/sys/socket/linux/accept4.cpp
@@ -0,0 +1,31 @@
+//===-- Linux implementation of accept4 -----------------------------------===//
+//
+// 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/socket/accept4.h"
+
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/accept4.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, accept4,
+                   (int sockfd, struct sockaddr *__restrict addr,
+                    socklen_t *__restrict addrlen, int flags)) {
+  auto result = linux_syscalls::accept4(sockfd, addr, addrlen, flags);
+  if (!result.has_value()) {
+    libc_errno = result.error();
+    return -1;
+  }
+
+  return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL

>From 60b060d7e5403fd261dd7d1e84fd5ca90109efc3 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 20 Apr 2026 14:29:20 +0000
Subject: [PATCH 3/3] more tests

---
 .../src/sys/socket/linux/connect_accept_test.cpp     | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/libc/test/src/sys/socket/linux/connect_accept_test.cpp b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
index c523d470f616f..5f62a030e08f8 100644
--- a/libc/test/src/sys/socket/linux/connect_accept_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_accept_test.cpp
@@ -143,6 +143,10 @@ TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
+  // This should fail as the other side is not listen()ing yet.
+  ASSERT_THAT(LIBC_NAMESPACE::accept4(accepting_socket, nullptr, nullptr, 0),
+              Fails(EINVAL));
+
   ASSERT_THAT(LIBC_NAMESPACE::listen(accepting_socket, 1), Succeeds(0));
 
   int connecting_socket = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
@@ -155,8 +159,11 @@ TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
                   sizeof(struct sockaddr_un)),
               Succeeds(0));
 
+  struct sockaddr_un accepted_addr;
+  socklen_t accepted_addr_len = sizeof(accepted_addr);
   int accepted_socket = LIBC_NAMESPACE::accept4(
-      accepting_socket, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
+      accepting_socket, reinterpret_cast<struct sockaddr *>(&accepted_addr),
+      &accepted_addr_len, SOCK_CLOEXEC | SOCK_NONBLOCK);
   ASSERT_GE(accepted_socket, 0);
   ASSERT_ERRNO_SUCCESS();
 
@@ -164,6 +171,9 @@ TEST_F(LlvmLibcConnectAcceptTest, Accept4Flags) {
   ASSERT_THAT(LIBC_NAMESPACE::close(accepting_socket), Succeeds(0));
   ASSERT_THAT(LIBC_NAMESPACE::remove(ACCEPT_PATH), Succeeds(0));
 
+  ASSERT_EQ(accepted_addr_len, sizeof(sa_family_t));
+  ASSERT_EQ(accepted_addr.sun_family, static_cast<sa_family_t>(AF_UNIX));
+
   // Check FD_CLOEXEC
   int fd_flags = LIBC_NAMESPACE::fcntl(accepted_socket, F_GETFD);
   ASSERT_GE(fd_flags, 0);



More information about the libc-commits mailing list