[libc-commits] [libc] [libc] Implement shutdown on linux (PR #192933)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Mon Apr 20 03:38:11 PDT 2026


https://github.com/labath created https://github.com/llvm/llvm-project/pull/192933

- added the relevant constant definitions
- enabled the entry point on x86_64, aarch64 and riscv
- testing by checking that the call causes an EOF on read (on the appropriate end)

>From 194e8747e2b1e82dfa9178ad28f7d8d544489077 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 20 Apr 2026 10:04:39 +0000
Subject: [PATCH] [libc] Implement shutdown on linux

- added the relevant constant definitions
- enabled the entry point on x86_64, aarch64 and riscv
- testing by checking that the call causes an EOF on read (on the
  appropriate end)
---
 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                 |  4 +
 libc/include/sys/socket.yaml                  |  7 ++
 .../OSUtil/linux/syscall_wrappers/shutdown.h  | 43 +++++++++++
 libc/src/sys/socket/CMakeLists.txt            |  7 ++
 libc/src/sys/socket/linux/CMakeLists.txt      | 12 +++
 libc/src/sys/socket/linux/shutdown.cpp        | 27 +++++++
 libc/src/sys/socket/shutdown.h                | 20 +++++
 libc/test/src/sys/socket/linux/CMakeLists.txt | 19 +++++
 .../src/sys/socket/linux/shutdown_test.cpp    | 77 +++++++++++++++++++
 12 files changed, 219 insertions(+)
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/shutdown.h
 create mode 100644 libc/src/sys/socket/linux/shutdown.cpp
 create mode 100644 libc/src/sys/socket/shutdown.h
 create mode 100644 libc/test/src/sys/socket/linux/shutdown_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 87bd5461496b3..d379aa6ec6211 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1219,6 +1219,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.sys.socket.getsockopt
     libc.src.sys.socket.listen
     libc.src.sys.socket.setsockopt
+    libc.src.sys.socket.shutdown
     libc.src.sys.socket.socket
   )
 endif()
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index ea117c1d83c24..e00748067619b 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1353,6 +1353,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.sys.socket.getsockopt
     libc.src.sys.socket.listen
     libc.src.sys.socket.setsockopt
+    libc.src.sys.socket.shutdown
     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 5c69c8808b2c1..e2fe9181e280f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1427,6 +1427,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.sys.socket.connect
     libc.src.sys.socket.getsockopt
     libc.src.sys.socket.listen
+    libc.src.sys.socket.shutdown
     libc.src.sys.socket.socketpair
     libc.src.sys.socket.setsockopt
     libc.src.sys.socket.send
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..8f95e1c6cd0cd 100644
--- a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
@@ -43,4 +43,8 @@
 #define SO_BSDCOMPAT 14
 #define SO_REUSEPORT 15
 
+#define SHUT_RD 0
+#define SHUT_WR 1
+#define SHUT_RDWR 2
+
 #endif // LLVM_LIBC_MACROS_LINUX_SYS_SOCKET_MACROS_H
diff --git a/libc/include/sys/socket.yaml b/libc/include/sys/socket.yaml
index 28a81328a3559..0eae5e5e0dd47 100644
--- a/libc/include/sys/socket.yaml
+++ b/libc/include/sys/socket.yaml
@@ -123,6 +123,13 @@ functions:
       - type: int
       - type: const void *
       - type: socklen_t
+  - name: shutdown
+    standards:
+      - POSIX
+    return_type: int
+    arguments:
+      - type: int
+      - type: int
   - name: socket
     standards:
       - POSIX
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/shutdown.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/shutdown.h
new file mode 100644
index 0000000000000..2a9e92364f637
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/shutdown.h
@@ -0,0 +1,43 @@
+//===-- Implementation header for shutdown ----------------------*- 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_SHUTDOWN_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SHUTDOWN_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_SHUTDOWN socketcall number.
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> shutdown(int sockfd, int how) {
+#ifdef SYS_shutdown
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_shutdown, sockfd, how);
+#elif defined(SYS_socketcall)
+  unsigned long sockcall_args[2] = {static_cast<unsigned long>(sockfd),
+                                    static_cast<unsigned long>(how)};
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_socketcall, SYS_SHUTDOWN,
+                                              sockcall_args);
+#else
+#error "shutdown 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_SHUTDOWN_H
diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt
index 50558c667c78a..68fbbad51e79f 100644
--- a/libc/src/sys/socket/CMakeLists.txt
+++ b/libc/src/sys/socket/CMakeLists.txt
@@ -99,3 +99,10 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_OS}.recvmsg
 )
+
+add_entrypoint_object(
+  shutdown
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.shutdown
+)
diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt
index c63a8e1fafe19..2a5ab16f4ca4f 100644
--- a/libc/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/src/sys/socket/linux/CMakeLists.txt
@@ -189,3 +189,15 @@ add_entrypoint_object(
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
+
+add_entrypoint_object(
+  shutdown
+  SRCS
+    shutdown.cpp
+  HDRS
+    ../shutdown.h
+  DEPENDS
+    libc.include.sys_socket
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/sys/socket/linux/shutdown.cpp b/libc/src/sys/socket/linux/shutdown.cpp
new file mode 100644
index 0000000000000..ba86e383fa867
--- /dev/null
+++ b/libc/src/sys/socket/linux/shutdown.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of shutdown ----------------------------------===//
+//
+// 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/shutdown.h"
+
+#include "src/__support/OSUtil/linux/syscall_wrappers/shutdown.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, shutdown, (int sockfd, int how)) {
+  auto result = linux_syscalls::shutdown(sockfd, how);
+  if (!result.has_value()) {
+    libc_errno = result.error();
+    return -1;
+  }
+
+  return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/socket/shutdown.h b/libc/src/sys/socket/shutdown.h
new file mode 100644
index 0000000000000..a757d6a0ddbce
--- /dev/null
+++ b/libc/src/sys/socket/shutdown.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for shutdown ----------------------*- 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_SHUTDOWN_H
+#define LLVM_LIBC_SRC_SYS_SOCKET_SHUTDOWN_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int shutdown(int sockfd, int how);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SOCKET_SHUTDOWN_H
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index af0a46e9a06bb..3f33b383738a4 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -165,3 +165,22 @@ add_libc_unittest(
     libc.test.UnitTest.ErrnoCheckingTest
     libc.test.UnitTest.ErrnoSetterMatcher
 )
+
+add_libc_unittest(
+  shutdown_test
+  SUITE
+    libc_sys_socket_unittests
+  SRCS
+    shutdown_test.cpp
+  DEPENDS
+    libc.include.sys_socket
+    libc.hdr.sys_socket_macros
+    libc.hdr.types.ssize_t
+    libc.src.errno.errno
+    libc.src.sys.socket.shutdown
+    libc.src.sys.socket.socketpair
+    libc.src.unistd.close
+    libc.src.unistd.read
+    libc.test.UnitTest.ErrnoCheckingTest
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/sys/socket/linux/shutdown_test.cpp b/libc/test/src/sys/socket/linux/shutdown_test.cpp
new file mode 100644
index 0000000000000..a8c1cef81b850
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/shutdown_test.cpp
@@ -0,0 +1,77 @@
+//===-- Unittests for shutdown --------------------------------------------===//
+//
+// 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/ssize_t.h"
+#include "src/sys/socket/shutdown.h"
+#include "src/sys/socket/socketpair.h"
+#include "src/unistd/close.h"
+#include "src/unistd/read.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 LlvmLibcShutdownTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcShutdownTest, ShutWrProducesEOF) {
+  int sv[2];
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sv),
+              Succeeds(0));
+
+  // Shut down write on sv[0].
+  ASSERT_THAT(LIBC_NAMESPACE::shutdown(sv[0], SHUT_WR), Succeeds(0));
+
+  // Reading from sv[1] should return 0 (EOF).
+  char read_buf[10];
+  ASSERT_EQ(LIBC_NAMESPACE::read(sv[1], read_buf, sizeof(read_buf)),
+            ssize_t(0));
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
+}
+
+TEST_F(LlvmLibcShutdownTest, ShutRdPreventsReading) {
+  int sv[2];
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sv),
+              Succeeds(0));
+
+  // Shut down read on sv[0].
+  ASSERT_THAT(LIBC_NAMESPACE::shutdown(sv[0], SHUT_RD), Succeeds(0));
+
+  // Reading from sv[0] should return 0 (EOF).
+  char read_buf[10];
+  ASSERT_EQ(LIBC_NAMESPACE::read(sv[0], read_buf, sizeof(read_buf)),
+            ssize_t(0));
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
+}
+
+TEST_F(LlvmLibcShutdownTest, ShutRdWrDoesBoth) {
+  int sv[2];
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sv),
+              Succeeds(0));
+
+  // Shut down read and write on sv[0].
+  ASSERT_THAT(LIBC_NAMESPACE::shutdown(sv[0], SHUT_RDWR), Succeeds(0));
+
+  // Reading from sv[0] should return 0 (EOF).
+  char read_buf[10];
+  ASSERT_EQ(LIBC_NAMESPACE::read(sv[0], read_buf, sizeof(read_buf)),
+            ssize_t(0));
+
+  // Reading from sv[1] should return 0 (EOF).
+  ASSERT_EQ(LIBC_NAMESPACE::read(sv[1], read_buf, sizeof(read_buf)),
+            ssize_t(0));
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sv[0]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(sv[1]), Succeeds(0));
+}



More information about the libc-commits mailing list