[libc-commits] [libc] [libc] Implement listen(2) on linux (PR #190755)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Thu Apr 9 03:03:13 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/190755
>From cc870f94d2882713fd275508b0028224b988b638 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 2 Apr 2026 12:42:29 +0000
Subject: [PATCH 1/3] [libc] Implement listen(2) on linux
I'm using the new syscall wrapper framework, and enabling the entry
point for x86_64, aarch64 and riscv. I also extend the connect test to
check for successful connection, now that we have that ability.
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
.../linux/syscall_wrappers/CMakeLists.txt | 12 ++++
.../OSUtil/linux/syscall_wrappers/listen.h | 43 ++++++++++++++
libc/src/sys/socket/CMakeLists.txt | 7 +++
libc/src/sys/socket/linux/CMakeLists.txt | 12 ++++
libc/src/sys/socket/linux/listen.cpp | 27 +++++++++
libc/src/sys/socket/listen.h | 20 +++++++
libc/test/src/sys/socket/linux/CMakeLists.txt | 21 +++++++
.../src/sys/socket/linux/connect_test.cpp | 11 +++-
.../test/src/sys/socket/linux/listen_test.cpp | 59 +++++++++++++++++++
12 files changed, 214 insertions(+), 1 deletion(-)
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h
create mode 100644 libc/src/sys/socket/linux/listen.cpp
create mode 100644 libc/src/sys/socket/listen.h
create mode 100644 libc/test/src/sys/socket/linux/listen_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 83088456fb4ac..567848795be49 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1210,6 +1210,7 @@ if(LLVM_LIBC_FULL_BUILD)
# sys/socket.h entrypoints
libc.src.sys.socket.bind
libc.src.sys.socket.connect
+ libc.src.sys.socket.listen
libc.src.sys.socket.socket
)
endif()
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 1f7180d23a840..997c08ee7de9b 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1344,6 +1344,7 @@ if(LLVM_LIBC_FULL_BUILD)
# sys/socket.h entrypoints
libc.src.sys.socket.bind
libc.src.sys.socket.connect
+ libc.src.sys.socket.listen
libc.src.sys.socket.socket
libc.src.sys.socket.socketpair
libc.src.sys.socket.send
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 20434fb9e838f..ea1cd80a1d0f1 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1415,6 +1415,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.sys.socket.socket
libc.src.sys.socket.bind
libc.src.sys.socket.connect
+ libc.src.sys.socket.listen
libc.src.sys.socket.socketpair
libc.src.sys.socket.send
libc.src.sys.socket.sendto
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 7f28ab7829d66..f7b95b07df473 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -38,6 +38,18 @@ add_header_library(
libc.include.sys_syscall
)
+add_header_library(
+ listen
+ HDRS
+ listen.h
+ DEPENDS
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
add_header_library(
read
HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h
new file mode 100644
index 0000000000000..d456a44a8502c
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h
@@ -0,0 +1,43 @@
+//===-- Implementation header for listen ------------------------*- 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_LISTEN_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LISTEN_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 <linux/net.h> // For SYS_SOCKET socketcall number.
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> listen(int sockfd, int backlog) {
+#ifdef SYS_listen
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_listen, sockfd, backlog);
+#elif defined(SYS_socketcall)
+ unsigned long sockcall_args[2] = {static_cast<unsigned long>(sockfd),
+ static_cast<unsigned long>(backlog)};
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_socketcall, SYS_LISTEN,
+ sockcall_args);
+#else
+#error "listen 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_LISTEN_H
diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt
index 5d9e2ff2d2f76..7859cde60cb85 100644
--- a/libc/src/sys/socket/CMakeLists.txt
+++ b/libc/src/sys/socket/CMakeLists.txt
@@ -23,6 +23,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.connect
)
+add_entrypoint_object(
+ listen
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.listen
+)
+
add_entrypoint_object(
socketpair
ALIAS
diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt
index 5be93e252cf52..2194d97ffcb7e 100644
--- a/libc/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/src/sys/socket/linux/CMakeLists.txt
@@ -38,6 +38,18 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ listen
+ SRCS
+ listen.cpp
+ HDRS
+ ../listen.h
+ DEPENDS
+ libc.include.sys_socket
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
socketpair
SRCS
diff --git a/libc/src/sys/socket/linux/listen.cpp b/libc/src/sys/socket/linux/listen.cpp
new file mode 100644
index 0000000000000..09d217a294f2d
--- /dev/null
+++ b/libc/src/sys/socket/linux/listen.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of listen ------------------------------------===//
+//
+// 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/listen.h"
+
+#include "src/__support/OSUtil/linux/syscall_wrappers/listen.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, listen, (int sockfd, int backlog)) {
+ auto result = linux_syscalls::listen(sockfd, backlog);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+
+ return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/socket/listen.h b/libc/src/sys/socket/listen.h
new file mode 100644
index 0000000000000..5b6477d63e7eb
--- /dev/null
+++ b/libc/src/sys/socket/listen.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for listen ------------------------*- 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_LISTEN_H
+#define LLVM_LIBC_SRC_SYS_SOCKET_LISTEN_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int listen(int sockfd, int backlog);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SOCKET_LISTEN_H
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index 95c0d622bdcdd..3cb2b3e251076 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -48,6 +48,27 @@ add_libc_unittest(
libc.src.sys.socket.socket
libc.src.sys.socket.bind
libc.src.sys.socket.connect
+ libc.src.sys.socket.listen
+ libc.src.stdio.remove
+ libc.src.unistd.close
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_unittest(
+ listen_test
+ SUITE
+ libc_sys_socket_unittests
+ SRCS
+ listen_test.cpp
+ DEPENDS
+ libc.include.sys_socket
+ libc.hdr.sys_socket_macros
+ libc.hdr.types.struct_sockaddr_un
+ libc.src.errno.errno
+ libc.src.sys.socket.socket
+ libc.src.sys.socket.bind
+ libc.src.sys.socket.listen
libc.src.stdio.remove
libc.src.unistd.close
libc.test.UnitTest.ErrnoCheckingTest
diff --git a/libc/test/src/sys/socket/linux/connect_test.cpp b/libc/test/src/sys/socket/linux/connect_test.cpp
index 05501eb7dd560..16b5b1cccfba1 100644
--- a/libc/test/src/sys/socket/linux/connect_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_test.cpp
@@ -11,6 +11,7 @@
#include "src/sys/socket/bind.h"
#include "src/sys/socket/connect.h"
#include "src/sys/socket/socket.h"
+#include "src/sys/socket/listen.h"
#include "src/stdio/remove.h"
#include "src/unistd/close.h"
@@ -60,7 +61,15 @@ TEST_F(LlvmLibcConnectTest, ConnectLocalSocket) {
LIBC_NAMESPACE::connect(sock2,
reinterpret_cast<struct sockaddr *>(&my_addr),
sizeof(struct sockaddr_un)),
- Fails(ECONNREFUSED)); // Because the other side is not listen()ing.
+ Fails(ECONNREFUSED)); // Because the other side is not listen()ing yet.
+
+ ASSERT_THAT(LIBC_NAMESPACE::listen(sock1, 1), Succeeds(0));
+
+ ASSERT_THAT(
+ LIBC_NAMESPACE::connect(sock2,
+ reinterpret_cast<struct sockaddr *>(&my_addr),
+ sizeof(struct sockaddr_un)),
+ Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(sock1), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(sock2), Succeeds(0));
diff --git a/libc/test/src/sys/socket/linux/listen_test.cpp b/libc/test/src/sys/socket/linux/listen_test.cpp
new file mode 100644
index 0000000000000..71553a8a62862
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/listen_test.cpp
@@ -0,0 +1,59 @@
+//===-- Unittests for listen ----------------------------------------------===//
+//
+// 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 "hdr/sys_socket_macros.h"
+#include "hdr/types/struct_sockaddr_un.h"
+#include "src/sys/socket/bind.h"
+#include "src/sys/socket/listen.h"
+#include "src/sys/socket/socket.h"
+
+#include "src/stdio/remove.h"
+#include "src/unistd/close.h"
+
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcListenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcListenTest, ListenLocalSocket) {
+
+ const char *FILENAME = "listen_file.test";
+ auto SOCK_PATH = libc_make_test_file_path(FILENAME);
+
+ int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_GE(sock, 0);
+ ASSERT_ERRNO_SUCCESS();
+
+ struct sockaddr_un my_addr;
+
+ my_addr.sun_family = AF_UNIX;
+ unsigned int i = 0;
+ for (;
+ SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t));
+ ++i)
+ my_addr.sun_path[i] = SOCK_PATH[i];
+
+ my_addr.sun_path[i] = '\0';
+
+ ASSERT_THAT(
+ LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
+ sizeof(struct sockaddr_un)),
+ Succeeds(0));
+
+ ASSERT_THAT(LIBC_NAMESPACE::listen(sock, 5), Succeeds(0));
+
+ ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::remove(SOCK_PATH), Succeeds(0));
+}
+
+TEST_F(LlvmLibcListenTest, ListenFails) {
+ ASSERT_THAT(LIBC_NAMESPACE::listen(-1, 5), Fails(EBADF));
+}
>From b527543b13be190604f0f32cbba0be45f8d51bba Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Tue, 7 Apr 2026 09:27:31 +0000
Subject: [PATCH 2/3] format
---
libc/test/src/sys/socket/linux/connect_test.cpp | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/libc/test/src/sys/socket/linux/connect_test.cpp b/libc/test/src/sys/socket/linux/connect_test.cpp
index 16b5b1cccfba1..dc8d48d8e0b0b 100644
--- a/libc/test/src/sys/socket/linux/connect_test.cpp
+++ b/libc/test/src/sys/socket/linux/connect_test.cpp
@@ -10,8 +10,8 @@
#include "hdr/types/struct_sockaddr_un.h"
#include "src/sys/socket/bind.h"
#include "src/sys/socket/connect.h"
-#include "src/sys/socket/socket.h"
#include "src/sys/socket/listen.h"
+#include "src/sys/socket/socket.h"
#include "src/stdio/remove.h"
#include "src/unistd/close.h"
@@ -65,11 +65,10 @@ TEST_F(LlvmLibcConnectTest, ConnectLocalSocket) {
ASSERT_THAT(LIBC_NAMESPACE::listen(sock1, 1), Succeeds(0));
- ASSERT_THAT(
- LIBC_NAMESPACE::connect(sock2,
- reinterpret_cast<struct sockaddr *>(&my_addr),
- sizeof(struct sockaddr_un)),
- Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::connect(
+ sock2, reinterpret_cast<struct sockaddr *>(&my_addr),
+ sizeof(struct sockaddr_un)),
+ Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(sock1), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::close(sock2), Succeeds(0));
>From 590d711c3157f5ea1d6c204590ab24ea05e5dfd1 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 9 Apr 2026 12:03:02 +0200
Subject: [PATCH 3/3] fix comment
---
libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h
index d456a44a8502c..9de54ce0a9a9f 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/listen.h
@@ -14,7 +14,7 @@
#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
-#include <linux/net.h> // For SYS_SOCKET socketcall number.
+#include <linux/net.h> // For SYS_LISTEN socketcall number.
#include <sys/syscall.h> // For syscall numbers
namespace LIBC_NAMESPACE_DECL {
More information about the libc-commits
mailing list