[llvm] [llvm][Support] Implement raw_socket_stream::read with optional timeout (PR #92308)

Connor Sughrue via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 17 18:01:27 PDT 2024


https://github.com/cpsughrue updated https://github.com/llvm/llvm-project/pull/92308

>From a7f9b96dea4a090ad1ff9c1d06cb7584c8f1fed5 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Wed, 29 May 2024 09:26:07 -0400
Subject: [PATCH 1/7] WIP

---
 llvm/include/llvm/Support/FileDescriptor.h    | 32 +++++++
 llvm/lib/Support/CMakeLists.txt               |  3 +-
 llvm/lib/Support/FileDescriptor.cpp           | 91 +++++++++++++++++++
 llvm/lib/Support/raw_socket_stream.cpp        | 62 +------------
 .../gn/secondary/llvm/lib/Support/BUILD.gn    |  1 +
 5 files changed, 130 insertions(+), 59 deletions(-)
 create mode 100644 llvm/include/llvm/Support/FileDescriptor.h
 create mode 100644 llvm/lib/Support/FileDescriptor.cpp

diff --git a/llvm/include/llvm/Support/FileDescriptor.h b/llvm/include/llvm/Support/FileDescriptor.h
new file mode 100644
index 0000000000000..ab83b34fca0fa
--- /dev/null
+++ b/llvm/include/llvm/Support/FileDescriptor.h
@@ -0,0 +1,32 @@
+//===-- FileDescriptor.h ----------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a utility functions for working with file descriptors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILEDESCRIPTOR_H
+#define LLVM_SUPPORT_FILEDESCRIPTOR_H
+
+#include "llvm/Support/Error.h"
+#include <chrono>
+
+namespace llvm {
+// Helper function to get the value from either std::atomic<int> or int
+template <typename T> int getFD(T &FD) {
+  if constexpr (std::is_same_v<T, std::atomic<int>>) {
+    return FD.load();
+  } else {
+    return FD;
+  }
+}
+
+template <typename T>
+llvm::Error manageTimeout(std::chrono::milliseconds Timeout, T &FD, int PipeFD);
+} // namespace llvm
+#endif
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index be4badc09efa5..0a65e58da88a8 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -176,8 +176,9 @@ add_llvm_component_library(LLVMSupport
   ExponentialBackoff.cpp
   ExtensibleRTTI.cpp
   FileCollector.cpp
-  FileUtilities.cpp
+  FileDescriptor.cpp
   FileOutputBuffer.cpp
+  FileUtilities.cpp
   FloatingPointMode.cpp
   FoldingSet.cpp
   FormattedStream.cpp
diff --git a/llvm/lib/Support/FileDescriptor.cpp b/llvm/lib/Support/FileDescriptor.cpp
new file mode 100644
index 0000000000000..9ecf991fa5dc3
--- /dev/null
+++ b/llvm/lib/Support/FileDescriptor.cpp
@@ -0,0 +1,91 @@
+//===-- FileDescriptor.cpp --------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a utility functions for working with file descriptors
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileDescriptor.h"
+#include <atomic>
+#include <chrono>
+#include <poll.h>
+
+static std::error_code getLastSocketErrorCode() {
+#ifdef _WIN32
+  return std::error_code(::WSAGetLastError(), std::system_category());
+#else
+  return llvm::errnoAsErrorCode();
+#endif
+}
+
+template <typename T>
+llvm::Error llvm::manageTimeout(std::chrono::milliseconds Timeout, T &FD, int PipeFD) {
+  static_assert(std::is_same_v<T, int> || std::is_same_v<T, std::atomic<int>>,
+                "FD must be of type int& or std::atomic<int>&");
+
+  struct pollfd FDs[2];
+  FDs[0].events = POLLIN;
+#ifdef _WIN32
+  SOCKET WinServerSock = _get_osfhandle(FD);
+  FDs[0].fd = WinServerSock;
+#else
+  FDs[0].fd = llvm::getFD(FD);
+#endif
+  FDs[1].events = POLLIN;
+  FDs[1].fd = PipeFD;
+
+  // Keep track of how much time has passed in case poll is interupted by a
+  // signal and needs to be recalled
+  int RemainingTime = Timeout.count();
+  std::chrono::milliseconds ElapsedTime = std::chrono::milliseconds(0);
+  int PollStatus = -1;
+
+  while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
+    if (Timeout.count() != -1)
+      RemainingTime -= ElapsedTime.count();
+
+    auto Start = std::chrono::steady_clock::now();
+#ifdef _WIN32
+    PollStatus = WSAPoll(FDs, 2, RemainingTime);
+#else
+    PollStatus = ::poll(FDs, 2, RemainingTime);
+#endif
+    // If FD equals -1 then ListeningSocket::shutdown has been called and it is
+    // appropriate to return operation_canceled
+    if (FD == -1)
+      return llvm::make_error<llvm::StringError>(
+          std::make_error_code(std::errc::operation_canceled),
+          "Accept canceled");
+
+#if _WIN32
+    if (PollStatus == SOCKET_ERROR) {
+#else
+    if (PollStatus == -1) {
+#endif
+      std::error_code PollErrCode = getLastSocketErrorCode();
+      // Ignore EINTR (signal occured before any request event) and retry
+      if (PollErrCode != std::errc::interrupted)
+        return llvm::make_error<llvm::StringError>(PollErrCode,
+                                                   "FD poll failed");
+    }
+    if (PollStatus == 0)
+      return llvm::make_error<llvm::StringError>(
+          std::make_error_code(std::errc::timed_out),
+          "No client requests within timeout window");
+
+    if (FDs[0].revents & POLLNVAL)
+      return llvm::make_error<llvm::StringError>(
+          std::make_error_code(std::errc::bad_file_descriptor));
+
+    auto Stop = std::chrono::steady_clock::now();
+    ElapsedTime +=
+        std::chrono::duration_cast<std::chrono::milliseconds>(Stop - Start);
+  }
+  return llvm::Error::success();
+}
diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index 549d537709bf2..4f1b24377bd5e 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -14,6 +14,7 @@
 #include "llvm/Support/raw_socket_stream.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/FileDescriptor.h"
 #include "llvm/Support/FileSystem.h"
 
 #include <atomic>
@@ -179,64 +180,9 @@ Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
 
 Expected<std::unique_ptr<raw_socket_stream>>
 ListeningSocket::accept(std::chrono::milliseconds Timeout) {
-
-  struct pollfd FDs[2];
-  FDs[0].events = POLLIN;
-#ifdef _WIN32
-  SOCKET WinServerSock = _get_osfhandle(FD);
-  FDs[0].fd = WinServerSock;
-#else
-  FDs[0].fd = FD;
-#endif
-  FDs[1].events = POLLIN;
-  FDs[1].fd = PipeFD[0];
-
-  // Keep track of how much time has passed in case poll is interupted by a
-  // signal and needs to be recalled
-  int RemainingTime = Timeout.count();
-  std::chrono::milliseconds ElapsedTime = std::chrono::milliseconds(0);
-  int PollStatus = -1;
-
-  while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
-    if (Timeout.count() != -1)
-      RemainingTime -= ElapsedTime.count();
-
-    auto Start = std::chrono::steady_clock::now();
-#ifdef _WIN32
-    PollStatus = WSAPoll(FDs, 2, RemainingTime);
-#else
-    PollStatus = ::poll(FDs, 2, RemainingTime);
-#endif
-    // If FD equals -1 then ListeningSocket::shutdown has been called and it is
-    // appropriate to return operation_canceled
-    if (FD.load() == -1)
-      return llvm::make_error<StringError>(
-          std::make_error_code(std::errc::operation_canceled),
-          "Accept canceled");
-
-#if _WIN32
-    if (PollStatus == SOCKET_ERROR) {
-#else
-    if (PollStatus == -1) {
-#endif
-      std::error_code PollErrCode = getLastSocketErrorCode();
-      // Ignore EINTR (signal occured before any request event) and retry
-      if (PollErrCode != std::errc::interrupted)
-        return llvm::make_error<StringError>(PollErrCode, "FD poll failed");
-    }
-    if (PollStatus == 0)
-      return llvm::make_error<StringError>(
-          std::make_error_code(std::errc::timed_out),
-          "No client requests within timeout window");
-
-    if (FDs[0].revents & POLLNVAL)
-      return llvm::make_error<StringError>(
-          std::make_error_code(std::errc::bad_file_descriptor));
-
-    auto Stop = std::chrono::steady_clock::now();
-    ElapsedTime +=
-        std::chrono::duration_cast<std::chrono::milliseconds>(Stop - Start);
-  }
+  llvm::Error TimeoutErr = manageTimeout(Timeout, FD, PipeFD[0]);
+  // if (TimeoutErr)
+  //   return TimeoutErr;
 
   int AcceptFD;
 #ifdef _WIN32
diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
index 7728455499bf3..79259abb80022 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
@@ -80,6 +80,7 @@ static_library("Support") {
     "ExponentialBackoff.cpp",
     "ExtensibleRTTI.cpp",
     "FileCollector.cpp",
+    "FileDescriptor.cpp",
     "FileOutputBuffer.cpp",
     "FileUtilities.cpp",
     "FloatingPointMode.cpp",

>From d76de7f29d5ae39533605a2aaddb845dcc80efeb Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 2 Jun 2024 13:58:31 -0400
Subject: [PATCH 2/7] Revert "WIP"

This reverts commit a7f9b96dea4a090ad1ff9c1d06cb7584c8f1fed5.
---
 llvm/include/llvm/Support/FileDescriptor.h    | 32 -------
 llvm/lib/Support/CMakeLists.txt               |  3 +-
 llvm/lib/Support/FileDescriptor.cpp           | 91 -------------------
 llvm/lib/Support/raw_socket_stream.cpp        | 62 ++++++++++++-
 .../gn/secondary/llvm/lib/Support/BUILD.gn    |  1 -
 5 files changed, 59 insertions(+), 130 deletions(-)
 delete mode 100644 llvm/include/llvm/Support/FileDescriptor.h
 delete mode 100644 llvm/lib/Support/FileDescriptor.cpp

diff --git a/llvm/include/llvm/Support/FileDescriptor.h b/llvm/include/llvm/Support/FileDescriptor.h
deleted file mode 100644
index ab83b34fca0fa..0000000000000
--- a/llvm/include/llvm/Support/FileDescriptor.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===-- FileDescriptor.h ----------------------------------------*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains a utility functions for working with file descriptors
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_FILEDESCRIPTOR_H
-#define LLVM_SUPPORT_FILEDESCRIPTOR_H
-
-#include "llvm/Support/Error.h"
-#include <chrono>
-
-namespace llvm {
-// Helper function to get the value from either std::atomic<int> or int
-template <typename T> int getFD(T &FD) {
-  if constexpr (std::is_same_v<T, std::atomic<int>>) {
-    return FD.load();
-  } else {
-    return FD;
-  }
-}
-
-template <typename T>
-llvm::Error manageTimeout(std::chrono::milliseconds Timeout, T &FD, int PipeFD);
-} // namespace llvm
-#endif
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 0a65e58da88a8..be4badc09efa5 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -176,9 +176,8 @@ add_llvm_component_library(LLVMSupport
   ExponentialBackoff.cpp
   ExtensibleRTTI.cpp
   FileCollector.cpp
-  FileDescriptor.cpp
-  FileOutputBuffer.cpp
   FileUtilities.cpp
+  FileOutputBuffer.cpp
   FloatingPointMode.cpp
   FoldingSet.cpp
   FormattedStream.cpp
diff --git a/llvm/lib/Support/FileDescriptor.cpp b/llvm/lib/Support/FileDescriptor.cpp
deleted file mode 100644
index 9ecf991fa5dc3..0000000000000
--- a/llvm/lib/Support/FileDescriptor.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-//===-- FileDescriptor.cpp --------------------------------------*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains a utility functions for working with file descriptors
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileDescriptor.h"
-#include <atomic>
-#include <chrono>
-#include <poll.h>
-
-static std::error_code getLastSocketErrorCode() {
-#ifdef _WIN32
-  return std::error_code(::WSAGetLastError(), std::system_category());
-#else
-  return llvm::errnoAsErrorCode();
-#endif
-}
-
-template <typename T>
-llvm::Error llvm::manageTimeout(std::chrono::milliseconds Timeout, T &FD, int PipeFD) {
-  static_assert(std::is_same_v<T, int> || std::is_same_v<T, std::atomic<int>>,
-                "FD must be of type int& or std::atomic<int>&");
-
-  struct pollfd FDs[2];
-  FDs[0].events = POLLIN;
-#ifdef _WIN32
-  SOCKET WinServerSock = _get_osfhandle(FD);
-  FDs[0].fd = WinServerSock;
-#else
-  FDs[0].fd = llvm::getFD(FD);
-#endif
-  FDs[1].events = POLLIN;
-  FDs[1].fd = PipeFD;
-
-  // Keep track of how much time has passed in case poll is interupted by a
-  // signal and needs to be recalled
-  int RemainingTime = Timeout.count();
-  std::chrono::milliseconds ElapsedTime = std::chrono::milliseconds(0);
-  int PollStatus = -1;
-
-  while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
-    if (Timeout.count() != -1)
-      RemainingTime -= ElapsedTime.count();
-
-    auto Start = std::chrono::steady_clock::now();
-#ifdef _WIN32
-    PollStatus = WSAPoll(FDs, 2, RemainingTime);
-#else
-    PollStatus = ::poll(FDs, 2, RemainingTime);
-#endif
-    // If FD equals -1 then ListeningSocket::shutdown has been called and it is
-    // appropriate to return operation_canceled
-    if (FD == -1)
-      return llvm::make_error<llvm::StringError>(
-          std::make_error_code(std::errc::operation_canceled),
-          "Accept canceled");
-
-#if _WIN32
-    if (PollStatus == SOCKET_ERROR) {
-#else
-    if (PollStatus == -1) {
-#endif
-      std::error_code PollErrCode = getLastSocketErrorCode();
-      // Ignore EINTR (signal occured before any request event) and retry
-      if (PollErrCode != std::errc::interrupted)
-        return llvm::make_error<llvm::StringError>(PollErrCode,
-                                                   "FD poll failed");
-    }
-    if (PollStatus == 0)
-      return llvm::make_error<llvm::StringError>(
-          std::make_error_code(std::errc::timed_out),
-          "No client requests within timeout window");
-
-    if (FDs[0].revents & POLLNVAL)
-      return llvm::make_error<llvm::StringError>(
-          std::make_error_code(std::errc::bad_file_descriptor));
-
-    auto Stop = std::chrono::steady_clock::now();
-    ElapsedTime +=
-        std::chrono::duration_cast<std::chrono::milliseconds>(Stop - Start);
-  }
-  return llvm::Error::success();
-}
diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index 4f1b24377bd5e..549d537709bf2 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -14,7 +14,6 @@
 #include "llvm/Support/raw_socket_stream.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/Error.h"
-#include "llvm/Support/FileDescriptor.h"
 #include "llvm/Support/FileSystem.h"
 
 #include <atomic>
@@ -180,9 +179,64 @@ Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
 
 Expected<std::unique_ptr<raw_socket_stream>>
 ListeningSocket::accept(std::chrono::milliseconds Timeout) {
-  llvm::Error TimeoutErr = manageTimeout(Timeout, FD, PipeFD[0]);
-  // if (TimeoutErr)
-  //   return TimeoutErr;
+
+  struct pollfd FDs[2];
+  FDs[0].events = POLLIN;
+#ifdef _WIN32
+  SOCKET WinServerSock = _get_osfhandle(FD);
+  FDs[0].fd = WinServerSock;
+#else
+  FDs[0].fd = FD;
+#endif
+  FDs[1].events = POLLIN;
+  FDs[1].fd = PipeFD[0];
+
+  // Keep track of how much time has passed in case poll is interupted by a
+  // signal and needs to be recalled
+  int RemainingTime = Timeout.count();
+  std::chrono::milliseconds ElapsedTime = std::chrono::milliseconds(0);
+  int PollStatus = -1;
+
+  while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
+    if (Timeout.count() != -1)
+      RemainingTime -= ElapsedTime.count();
+
+    auto Start = std::chrono::steady_clock::now();
+#ifdef _WIN32
+    PollStatus = WSAPoll(FDs, 2, RemainingTime);
+#else
+    PollStatus = ::poll(FDs, 2, RemainingTime);
+#endif
+    // If FD equals -1 then ListeningSocket::shutdown has been called and it is
+    // appropriate to return operation_canceled
+    if (FD.load() == -1)
+      return llvm::make_error<StringError>(
+          std::make_error_code(std::errc::operation_canceled),
+          "Accept canceled");
+
+#if _WIN32
+    if (PollStatus == SOCKET_ERROR) {
+#else
+    if (PollStatus == -1) {
+#endif
+      std::error_code PollErrCode = getLastSocketErrorCode();
+      // Ignore EINTR (signal occured before any request event) and retry
+      if (PollErrCode != std::errc::interrupted)
+        return llvm::make_error<StringError>(PollErrCode, "FD poll failed");
+    }
+    if (PollStatus == 0)
+      return llvm::make_error<StringError>(
+          std::make_error_code(std::errc::timed_out),
+          "No client requests within timeout window");
+
+    if (FDs[0].revents & POLLNVAL)
+      return llvm::make_error<StringError>(
+          std::make_error_code(std::errc::bad_file_descriptor));
+
+    auto Stop = std::chrono::steady_clock::now();
+    ElapsedTime +=
+        std::chrono::duration_cast<std::chrono::milliseconds>(Stop - Start);
+  }
 
   int AcceptFD;
 #ifdef _WIN32
diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
index 79259abb80022..7728455499bf3 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
@@ -80,7 +80,6 @@ static_library("Support") {
     "ExponentialBackoff.cpp",
     "ExtensibleRTTI.cpp",
     "FileCollector.cpp",
-    "FileDescriptor.cpp",
     "FileOutputBuffer.cpp",
     "FileUtilities.cpp",
     "FloatingPointMode.cpp",

>From 1249e4d1fa4aa330ff3d8008ccd49b98514bacd5 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 2 Jun 2024 15:04:21 -0400
Subject: [PATCH 3/7] Create static manageTimeout function

---
 llvm/lib/Support/raw_socket_stream.cpp | 44 +++++++++++++++-----------
 1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index 549d537709bf2..76f148acf491b 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -177,43 +177,43 @@ Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
 #endif // _WIN32
 }
 
-Expected<std::unique_ptr<raw_socket_stream>>
-ListeningSocket::accept(std::chrono::milliseconds Timeout) {
-
-  struct pollfd FDs[2];
-  FDs[0].events = POLLIN;
+static llvm::Error manageTimeout(std::atomic<int> &ActiveFD, int CancelFD,
+                                 std::chrono::milliseconds Timeout) {
+  struct pollfd FD[2];
+  FD[0].events = POLLIN;
 #ifdef _WIN32
   SOCKET WinServerSock = _get_osfhandle(FD);
-  FDs[0].fd = WinServerSock;
+  FD[0].fd = WinServerSock;
 #else
-  FDs[0].fd = FD;
+  FD[0].fd = ActiveFD.load();
 #endif
-  FDs[1].events = POLLIN;
-  FDs[1].fd = PipeFD[0];
+  FD[1].events = POLLIN;
+  FD[1].fd = CancelFD;
 
-  // Keep track of how much time has passed in case poll is interupted by a
-  // signal and needs to be recalled
+  // Keep track of how much time has passed in case ::poll or WSAPoll are
+  // interupted by a signal and need to be recalled
   int RemainingTime = Timeout.count();
   std::chrono::milliseconds ElapsedTime = std::chrono::milliseconds(0);
   int PollStatus = -1;
 
   while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
+    // Timeout of -1 indicates that no Timeout was provided
     if (Timeout.count() != -1)
       RemainingTime -= ElapsedTime.count();
-
     auto Start = std::chrono::steady_clock::now();
+
 #ifdef _WIN32
-    PollStatus = WSAPoll(FDs, 2, RemainingTime);
+    PollStatus = WSAPoll(FD, 2, RemainingTime);
 #else
-    PollStatus = ::poll(FDs, 2, RemainingTime);
+    PollStatus = ::poll(FD, 2, RemainingTime);
 #endif
+
     // If FD equals -1 then ListeningSocket::shutdown has been called and it is
     // appropriate to return operation_canceled
-    if (FD.load() == -1)
+    if (ActiveFD.load() == -1)
       return llvm::make_error<StringError>(
           std::make_error_code(std::errc::operation_canceled),
           "Accept canceled");
-
 #if _WIN32
     if (PollStatus == SOCKET_ERROR) {
 #else
@@ -222,14 +222,14 @@ ListeningSocket::accept(std::chrono::milliseconds Timeout) {
       std::error_code PollErrCode = getLastSocketErrorCode();
       // Ignore EINTR (signal occured before any request event) and retry
       if (PollErrCode != std::errc::interrupted)
-        return llvm::make_error<StringError>(PollErrCode, "FD poll failed");
+        return llvm::make_error<StringError>(PollErrCode, "poll failed");
     }
     if (PollStatus == 0)
       return llvm::make_error<StringError>(
           std::make_error_code(std::errc::timed_out),
           "No client requests within timeout window");
 
-    if (FDs[0].revents & POLLNVAL)
+    if (FD[0].revents & POLLNVAL)
       return llvm::make_error<StringError>(
           std::make_error_code(std::errc::bad_file_descriptor));
 
@@ -237,6 +237,14 @@ ListeningSocket::accept(std::chrono::milliseconds Timeout) {
     ElapsedTime +=
         std::chrono::duration_cast<std::chrono::milliseconds>(Stop - Start);
   }
+  return llvm::Error::success();
+}
+
+Expected<std::unique_ptr<raw_socket_stream>>
+ListeningSocket::accept(std::chrono::milliseconds Timeout) {
+  llvm::Error TimeoutErr = manageTimeout(FD, PipeFD[0], Timeout);
+  if (TimeoutErr)
+    return TimeoutErr;
 
   int AcceptFD;
 #ifdef _WIN32

>From 5d6749e63e5c725f0092bd290c60974dfdc8fdff Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 2 Jun 2024 22:06:42 -0400
Subject: [PATCH 4/7] Initial implementation of
 raw_socket_stream::readFromSocket with timeout

---
 llvm/include/llvm/Support/raw_socket_stream.h |  21 +++-
 llvm/lib/Support/raw_socket_stream.cpp        |  62 ++++++++--
 .../Support/raw_socket_stream_test.cpp        | 107 ++++++++++++++++--
 3 files changed, 164 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/Support/raw_socket_stream.h b/llvm/include/llvm/Support/raw_socket_stream.h
index bddd47eb75e1a..225980cb28a42 100644
--- a/llvm/include/llvm/Support/raw_socket_stream.h
+++ b/llvm/include/llvm/Support/raw_socket_stream.h
@@ -92,10 +92,11 @@ class ListeningSocket {
   /// Accepts an incoming connection on the listening socket. This method can
   /// optionally either block until a connection is available or timeout after a
   /// specified amount of time has passed. By default the method will block
-  /// until the socket has recieved a connection.
+  /// until the socket has recieved a connection. If the accept timesout this
+  /// method will return std::errc:timed_out
   ///
   /// \param Timeout An optional timeout duration in milliseconds. Setting
-  /// Timeout to -1 causes accept to block indefinitely
+  /// Timeout to a negative number causes ::accept to block indefinitely
   ///
   Expected<std::unique_ptr<raw_socket_stream>>
   accept(std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1));
@@ -124,11 +125,25 @@ class raw_socket_stream : public raw_fd_stream {
 
 public:
   raw_socket_stream(int SocketFD);
+  ~raw_socket_stream();
+
   /// Create a \p raw_socket_stream connected to the UNIX domain socket at \p
   /// SocketPath.
   static Expected<std::unique_ptr<raw_socket_stream>>
   createConnectedUnix(StringRef SocketPath);
-  ~raw_socket_stream();
+
+  /// Attempt to read from the raw_socket_stream's file descriptor. This method
+  /// can optionally either block until data is read or an error has occurred or
+  /// timeout after a specified amount of time has passed. By default the method
+  /// will block until the socket has read data or encountered an error. If the
+  /// read timesout this method will return std::errc:timed_out
+  ///
+  /// \param Timeout An optional timeout duration in milliseconds
+  /// \param Ptr The start of the buffer that will hold any read data
+  /// \param Size The number of bytes to be read
+  ///
+  Expected<std::string> readFromSocket(
+      std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1));
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index 76f148acf491b..cfc39ecd90c13 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -18,6 +18,7 @@
 
 #include <atomic>
 #include <fcntl.h>
+#include <functional>
 #include <thread>
 
 #ifndef _WIN32
@@ -177,18 +178,27 @@ Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
 #endif // _WIN32
 }
 
-static llvm::Error manageTimeout(std::atomic<int> &ActiveFD, int CancelFD,
-                                 std::chrono::milliseconds Timeout) {
+// If a file descriptor being monitored by poll is closed by another thread, the
+// result is unspecified. In the case poll does not unblock and return when
+// ActiveFD is closed you can provide another file descriptor via CancelFD that
+// when written to will cause poll to return
+static llvm::Error manageTimeout(std::chrono::milliseconds Timeout,
+                                 std::function<int()> getActiveFD,
+                                 std::optional<int> CancelFD = std::nullopt) {
   struct pollfd FD[2];
   FD[0].events = POLLIN;
 #ifdef _WIN32
   SOCKET WinServerSock = _get_osfhandle(FD);
   FD[0].fd = WinServerSock;
 #else
-  FD[0].fd = ActiveFD.load();
+  FD[0].fd = getActiveFD();
 #endif
-  FD[1].events = POLLIN;
-  FD[1].fd = CancelFD;
+  uint8_t FDCount = 1;
+  if (CancelFD.has_value()) {
+    FD[1].events = POLLIN;
+    FD[1].fd = CancelFD.value();
+    FDCount++;
+  }
 
   // Keep track of how much time has passed in case ::poll or WSAPoll are
   // interupted by a signal and need to be recalled
@@ -197,20 +207,19 @@ static llvm::Error manageTimeout(std::atomic<int> &ActiveFD, int CancelFD,
   int PollStatus = -1;
 
   while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
-    // Timeout of -1 indicates that no Timeout was provided
     if (Timeout.count() != -1)
       RemainingTime -= ElapsedTime.count();
     auto Start = std::chrono::steady_clock::now();
 
 #ifdef _WIN32
-    PollStatus = WSAPoll(FD, 2, RemainingTime);
+    PollStatus = WSAPoll(FD, FDCount, RemainingTime);
 #else
-    PollStatus = ::poll(FD, 2, RemainingTime);
+    PollStatus = ::poll(FD, FDCount, RemainingTime);
 #endif
 
     // If FD equals -1 then ListeningSocket::shutdown has been called and it is
     // appropriate to return operation_canceled
-    if (ActiveFD.load() == -1)
+    if (getActiveFD() == -1)
       return llvm::make_error<StringError>(
           std::make_error_code(std::errc::operation_canceled),
           "Accept canceled");
@@ -242,13 +251,14 @@ static llvm::Error manageTimeout(std::atomic<int> &ActiveFD, int CancelFD,
 
 Expected<std::unique_ptr<raw_socket_stream>>
 ListeningSocket::accept(std::chrono::milliseconds Timeout) {
-  llvm::Error TimeoutErr = manageTimeout(FD, PipeFD[0], Timeout);
+  auto getActiveFD = [this]() -> int { return FD; };
+  llvm::Error TimeoutErr = manageTimeout(Timeout, getActiveFD, PipeFD[0]);
   if (TimeoutErr)
     return TimeoutErr;
 
   int AcceptFD;
 #ifdef _WIN32
-  SOCKET WinAcceptSock = ::accept(WinServerSock, NULL, NULL);
+  SOCKET WinAcceptSock = ::accept(_get_osfhandle(FD), NULL, NULL);
   AcceptFD = _open_osfhandle(WinAcceptSock, 0);
 #else
   AcceptFD = ::accept(FD, NULL, NULL);
@@ -303,6 +313,8 @@ ListeningSocket::~ListeningSocket() {
 raw_socket_stream::raw_socket_stream(int SocketFD)
     : raw_fd_stream(SocketFD, true) {}
 
+raw_socket_stream::~raw_socket_stream() {}
+
 Expected<std::unique_ptr<raw_socket_stream>>
 raw_socket_stream::createConnectedUnix(StringRef SocketPath) {
 #ifdef _WIN32
@@ -314,4 +326,30 @@ raw_socket_stream::createConnectedUnix(StringRef SocketPath) {
   return std::make_unique<raw_socket_stream>(*FD);
 }
 
-raw_socket_stream::~raw_socket_stream() {}
+Expected<std::string>
+raw_socket_stream::readFromSocket(std::chrono::milliseconds Timeout) {
+  auto getActiveFD = [this]() -> int { return this->get_fd(); };
+  llvm::Error TimeoutErr = manageTimeout(Timeout, getActiveFD);
+  if (TimeoutErr)
+    return TimeoutErr;
+
+  std::vector<char> Buffer;
+  constexpr ssize_t TmpBufferSize = 1024;
+  char TmpBuffer[TmpBufferSize];
+
+  while (true) {
+    std::memset(TmpBuffer, 0, TmpBufferSize);
+    ssize_t BytesRead = this->read(TmpBuffer, TmpBufferSize);
+    if (BytesRead == -1)
+      return llvm::make_error<StringError>(this->error(), "read failed");
+    else if (BytesRead == 0)
+      break;
+    else
+      Buffer.insert(Buffer.end(), TmpBuffer, TmpBuffer + BytesRead);
+    // All available bytes have been read. Another call to read will block
+    if (BytesRead < TmpBufferSize)
+      break;
+  }
+
+  return std::string(Buffer.begin(), Buffer.end());
+}
diff --git a/llvm/unittests/Support/raw_socket_stream_test.cpp b/llvm/unittests/Support/raw_socket_stream_test.cpp
index c4e8cfbbe7e6a..1b8f85f88f1af 100644
--- a/llvm/unittests/Support/raw_socket_stream_test.cpp
+++ b/llvm/unittests/Support/raw_socket_stream_test.cpp
@@ -58,21 +58,106 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
   Client << "01234567";
   Client.flush();
 
-  char Bytes[8];
-  ssize_t BytesRead = Server.read(Bytes, 8);
+  llvm::Expected<std::string> MaybeText = Server.readFromSocket();
+  ASSERT_THAT_EXPECTED(MaybeText, llvm::Succeeded());
+  ASSERT_EQ("01234567", *MaybeText);
+}
+
+TEST(raw_socket_streamTest, LARGE_READ) {
+  if (!hasUnixSocketSupport())
+    GTEST_SKIP();
+
+  SmallString<100> SocketPath;
+  llvm::sys::fs::createUniquePath("large_read.sock", SocketPath, true);
+
+  // Make sure socket file does not exist. May still be there from the last test
+  std::remove(SocketPath.c_str());
+
+  Expected<ListeningSocket> MaybeServerListener =
+      ListeningSocket::createUnix(SocketPath);
+  ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
+  ListeningSocket ServerListener = std::move(*MaybeServerListener);
+
+  Expected<std::unique_ptr<raw_socket_stream>> MaybeClient =
+      raw_socket_stream::createConnectedUnix(SocketPath);
+  ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded());
+  raw_socket_stream &Client = **MaybeClient;
+
+  Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
+      ServerListener.accept();
+  ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded());
+  raw_socket_stream &Server = **MaybeServer;
+
+  // raw_socket_stream::readFromSocket pre-allocates a buffer 1024 bytes large.
+  // Test to make sure readFromSocket can handle messages larger then size of
+  // pre-allocated block
+  constexpr int TextLength = 1342;
+  constexpr char Text[TextLength] =
+      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
+      "eiusmod tempor incididunt ut labore et dolore magna aliqua. Vel orci "
+      "porta non pulvinar neque laoreet suspendisse interdum consectetur. "
+      "Nulla facilisi etiam dignissim diam quis. Porttitor massa id neque "
+      "aliquam vestibulum morbi blandit cursus. Purus viverra accumsan in "
+      "nisl. Nunc non blandit massa enim nec dui nunc mattis enim. Rhoncus "
+      "dolor purus non enim praesent elementum facilisis leo. Parturient "
+      "montes nascetur ridiculus mus mauris. Urna condimentum mattis "
+      "pellentesque id nibh tortor id aliquet lectus. Orci eu lobortis "
+      "elementum nibh. Sagittis eu volutpat odio facilisis. Molestie a "
+      "iaculis at erat pellentesque adipiscing. Tincidunt augue interdum "
+      "velit euismod in pellentesque massa placerat. Cras ornare arcu dui "
+      "vivamus arcu felis bibendum ut tristique. Tellus elementum sagittis "
+      "vitae et leo duis. Scelerisque fermentum dui faucibus in ornare "
+      "quam. Ipsum a arcu cursus vitae congue. Sit amet nisl suscipit "
+      "adipiscing. Sociis natoque penatibus et magnis. Cras semper auctor "
+      "neque vitae tempus quam pellentesque. Neque gravida in fermentum et "
+      "sollicitudin ac orci phasellus egestas. Vitae suscipit tellus mauris "
+      "a diam maecenas sed. Lectus arcu bibendum at varius vel pharetra. "
+      "Dignissim sodales ut eu sem integer vitae justo. Id cursus metus "
+      "aliquam eleifend mi.";
+  Client << Text;
+  Client.flush();
+
+  llvm::Expected<std::string> MaybeText = Server.readFromSocket();
+  ASSERT_THAT_EXPECTED(MaybeText, llvm::Succeeded());
+  ASSERT_EQ(Text, *MaybeText);
+}
 
-  std::string string(Bytes, 8);
+TEST(raw_socket_streamTest, READ_WITH_TIMEOUT) {
+  if (!hasUnixSocketSupport())
+    GTEST_SKIP();
+
+  SmallString<100> SocketPath;
+  llvm::sys::fs::createUniquePath("read_with_timeout.sock", SocketPath, true);
 
-  ASSERT_EQ(8, BytesRead);
-  ASSERT_EQ("01234567", string);
+  // Make sure socket file does not exist. May still be there from the last test
+  std::remove(SocketPath.c_str());
+
+  Expected<ListeningSocket> MaybeServerListener =
+      ListeningSocket::createUnix(SocketPath);
+  ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
+  ListeningSocket ServerListener = std::move(*MaybeServerListener);
+
+  Expected<std::unique_ptr<raw_socket_stream>> MaybeClient =
+      raw_socket_stream::createConnectedUnix(SocketPath);
+  ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded());
+
+  Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
+      ServerListener.accept();
+  ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded());
+  raw_socket_stream &Server = **MaybeServer;
+
+  llvm::Expected<std::string> MaybeBytesRead =
+      Server.readFromSocket(std::chrono::milliseconds(100));
+  ASSERT_EQ(llvm::errorToErrorCode(MaybeBytesRead.takeError()),
+            std::errc::timed_out);
 }
 
-TEST(raw_socket_streamTest, TIMEOUT_PROVIDED) {
+TEST(raw_socket_streamTest, ACCEPT_WITH_TIMEOUT) {
   if (!hasUnixSocketSupport())
     GTEST_SKIP();
 
   SmallString<100> SocketPath;
-  llvm::sys::fs::createUniquePath("timout_provided.sock", SocketPath, true);
+  llvm::sys::fs::createUniquePath("accept_with_timeout.sock", SocketPath, true);
 
   // Make sure socket file does not exist. May still be there from the last test
   std::remove(SocketPath.c_str());
@@ -82,19 +167,19 @@ TEST(raw_socket_streamTest, TIMEOUT_PROVIDED) {
   ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
   ListeningSocket ServerListener = std::move(*MaybeServerListener);
 
-  std::chrono::milliseconds Timeout = std::chrono::milliseconds(100);
   Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
-      ServerListener.accept(Timeout);
+      ServerListener.accept(std::chrono::milliseconds(100));
   ASSERT_EQ(llvm::errorToErrorCode(MaybeServer.takeError()),
             std::errc::timed_out);
 }
 
-TEST(raw_socket_streamTest, FILE_DESCRIPTOR_CLOSED) {
+TEST(raw_socket_streamTest, ACCEPT_WITH_SHUTDOWN) {
   if (!hasUnixSocketSupport())
     GTEST_SKIP();
 
   SmallString<100> SocketPath;
-  llvm::sys::fs::createUniquePath("fd_closed.sock", SocketPath, true);
+  llvm::sys::fs::createUniquePath("accept_with_shutdown.sock", SocketPath,
+                                  true);
 
   // Make sure socket file does not exist. May still be there from the last test
   std::remove(SocketPath.c_str());

>From a31daa2fd626dbcb598258140ccf4fa92e2bad58 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 2 Jun 2024 22:22:04 -0400
Subject: [PATCH 5/7] Include check to see if CloseFD has been written to

---
 llvm/lib/Support/raw_socket_stream.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index cfc39ecd90c13..1cd70c95bd4de 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -181,7 +181,8 @@ Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
 // If a file descriptor being monitored by poll is closed by another thread, the
 // result is unspecified. In the case poll does not unblock and return when
 // ActiveFD is closed you can provide another file descriptor via CancelFD that
-// when written to will cause poll to return
+// when written to will cause poll to return. Typically CancelFD is the read end
+// of a unidirectional pipe.
 static llvm::Error manageTimeout(std::chrono::milliseconds Timeout,
                                  std::function<int()> getActiveFD,
                                  std::optional<int> CancelFD = std::nullopt) {
@@ -217,9 +218,9 @@ static llvm::Error manageTimeout(std::chrono::milliseconds Timeout,
     PollStatus = ::poll(FD, FDCount, RemainingTime);
 #endif
 
-    // If FD equals -1 then ListeningSocket::shutdown has been called and it is
-    // appropriate to return operation_canceled
-    if (getActiveFD() == -1)
+    // If ActiveFD equals -1 or CancelFD has data to be read then the operation
+    // has been canceled by another thread
+    if (getActiveFD() == -1 || FD[1].revents & POLLIN)
       return llvm::make_error<StringError>(
           std::make_error_code(std::errc::operation_canceled),
           "Accept canceled");

>From 4bb12e41be0f7ebfd1c81ef3abbb24e9981f81da Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 2 Jun 2024 22:53:33 -0400
Subject: [PATCH 6/7] Fix type passed to _get_osfhandle

---
 llvm/lib/Support/raw_socket_stream.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index 1cd70c95bd4de..063f6fc366da9 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -189,7 +189,7 @@ static llvm::Error manageTimeout(std::chrono::milliseconds Timeout,
   struct pollfd FD[2];
   FD[0].events = POLLIN;
 #ifdef _WIN32
-  SOCKET WinServerSock = _get_osfhandle(FD);
+  SOCKET WinServerSock = _get_osfhandle(getActiveFD());
   FD[0].fd = WinServerSock;
 #else
   FD[0].fd = getActiveFD();

>From 83b8a820ce2979390180688f1a3e8c4fc74ee50a Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Mon, 17 Jun 2024 16:50:37 -0400
Subject: [PATCH 7/7] Reimplement raw_socket_stream::read as an override or
 raw_fs_stream::read

---
 llvm/include/llvm/Support/raw_socket_stream.h | 19 ++---
 llvm/lib/Support/raw_socket_stream.cpp        | 26 ++-----
 .../Support/raw_socket_stream_test.cpp        | 71 +++----------------
 3 files changed, 24 insertions(+), 92 deletions(-)

diff --git a/llvm/include/llvm/Support/raw_socket_stream.h b/llvm/include/llvm/Support/raw_socket_stream.h
index 225980cb28a42..2fb2fab570599 100644
--- a/llvm/include/llvm/Support/raw_socket_stream.h
+++ b/llvm/include/llvm/Support/raw_socket_stream.h
@@ -132,18 +132,21 @@ class raw_socket_stream : public raw_fd_stream {
   static Expected<std::unique_ptr<raw_socket_stream>>
   createConnectedUnix(StringRef SocketPath);
 
-  /// Attempt to read from the raw_socket_stream's file descriptor. This method
-  /// can optionally either block until data is read or an error has occurred or
-  /// timeout after a specified amount of time has passed. By default the method
-  /// will block until the socket has read data or encountered an error. If the
-  /// read timesout this method will return std::errc:timed_out
+  /// Attempt to read from the raw_socket_stream's file descriptor.
+  ///
+  /// This method can optionally either block until data is read or an error has
+  /// occurred or timeout after a specified amount of time has passed. By
+  /// default the method will block until the socket has read data or
+  /// encountered an error. If the read times out this method will return
+  /// std::errc:timed_out
   ///
-  /// \param Timeout An optional timeout duration in milliseconds
   /// \param Ptr The start of the buffer that will hold any read data
   /// \param Size The number of bytes to be read
+  /// \param Timeout An optional timeout duration in milliseconds
   ///
-  Expected<std::string> readFromSocket(
-      std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1));
+  llvm::Expected<ssize_t>
+  read(char *Ptr, size_t Size,
+       std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1));
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index 063f6fc366da9..5af0f308cc141 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -327,30 +327,12 @@ raw_socket_stream::createConnectedUnix(StringRef SocketPath) {
   return std::make_unique<raw_socket_stream>(*FD);
 }
 
-Expected<std::string>
-raw_socket_stream::readFromSocket(std::chrono::milliseconds Timeout) {
+llvm::Expected<ssize_t>
+raw_socket_stream::read(char *Ptr, size_t Size,
+                        std::chrono::milliseconds Timeout) {
   auto getActiveFD = [this]() -> int { return this->get_fd(); };
   llvm::Error TimeoutErr = manageTimeout(Timeout, getActiveFD);
   if (TimeoutErr)
     return TimeoutErr;
-
-  std::vector<char> Buffer;
-  constexpr ssize_t TmpBufferSize = 1024;
-  char TmpBuffer[TmpBufferSize];
-
-  while (true) {
-    std::memset(TmpBuffer, 0, TmpBufferSize);
-    ssize_t BytesRead = this->read(TmpBuffer, TmpBufferSize);
-    if (BytesRead == -1)
-      return llvm::make_error<StringError>(this->error(), "read failed");
-    else if (BytesRead == 0)
-      break;
-    else
-      Buffer.insert(Buffer.end(), TmpBuffer, TmpBuffer + BytesRead);
-    // All available bytes have been read. Another call to read will block
-    if (BytesRead < TmpBufferSize)
-      break;
-  }
-
-  return std::string(Buffer.begin(), Buffer.end());
+  return raw_fd_stream::read(Ptr, Size);
 }
diff --git a/llvm/unittests/Support/raw_socket_stream_test.cpp b/llvm/unittests/Support/raw_socket_stream_test.cpp
index 1b8f85f88f1af..fcbabad86a6f0 100644
--- a/llvm/unittests/Support/raw_socket_stream_test.cpp
+++ b/llvm/unittests/Support/raw_socket_stream_test.cpp
@@ -58,68 +58,14 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
   Client << "01234567";
   Client.flush();
 
-  llvm::Expected<std::string> MaybeText = Server.readFromSocket();
-  ASSERT_THAT_EXPECTED(MaybeText, llvm::Succeeded());
-  ASSERT_EQ("01234567", *MaybeText);
-}
-
-TEST(raw_socket_streamTest, LARGE_READ) {
-  if (!hasUnixSocketSupport())
-    GTEST_SKIP();
+  char Bytes[8];
+  llvm::Expected<ssize_t> MaybeBytesRead = Server.read(Bytes, 8);
+  ASSERT_THAT_EXPECTED(MaybeBytesRead, llvm::Succeeded());
 
-  SmallString<100> SocketPath;
-  llvm::sys::fs::createUniquePath("large_read.sock", SocketPath, true);
-
-  // Make sure socket file does not exist. May still be there from the last test
-  std::remove(SocketPath.c_str());
-
-  Expected<ListeningSocket> MaybeServerListener =
-      ListeningSocket::createUnix(SocketPath);
-  ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
-  ListeningSocket ServerListener = std::move(*MaybeServerListener);
-
-  Expected<std::unique_ptr<raw_socket_stream>> MaybeClient =
-      raw_socket_stream::createConnectedUnix(SocketPath);
-  ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded());
-  raw_socket_stream &Client = **MaybeClient;
-
-  Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
-      ServerListener.accept();
-  ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded());
-  raw_socket_stream &Server = **MaybeServer;
-
-  // raw_socket_stream::readFromSocket pre-allocates a buffer 1024 bytes large.
-  // Test to make sure readFromSocket can handle messages larger then size of
-  // pre-allocated block
-  constexpr int TextLength = 1342;
-  constexpr char Text[TextLength] =
-      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
-      "eiusmod tempor incididunt ut labore et dolore magna aliqua. Vel orci "
-      "porta non pulvinar neque laoreet suspendisse interdum consectetur. "
-      "Nulla facilisi etiam dignissim diam quis. Porttitor massa id neque "
-      "aliquam vestibulum morbi blandit cursus. Purus viverra accumsan in "
-      "nisl. Nunc non blandit massa enim nec dui nunc mattis enim. Rhoncus "
-      "dolor purus non enim praesent elementum facilisis leo. Parturient "
-      "montes nascetur ridiculus mus mauris. Urna condimentum mattis "
-      "pellentesque id nibh tortor id aliquet lectus. Orci eu lobortis "
-      "elementum nibh. Sagittis eu volutpat odio facilisis. Molestie a "
-      "iaculis at erat pellentesque adipiscing. Tincidunt augue interdum "
-      "velit euismod in pellentesque massa placerat. Cras ornare arcu dui "
-      "vivamus arcu felis bibendum ut tristique. Tellus elementum sagittis "
-      "vitae et leo duis. Scelerisque fermentum dui faucibus in ornare "
-      "quam. Ipsum a arcu cursus vitae congue. Sit amet nisl suscipit "
-      "adipiscing. Sociis natoque penatibus et magnis. Cras semper auctor "
-      "neque vitae tempus quam pellentesque. Neque gravida in fermentum et "
-      "sollicitudin ac orci phasellus egestas. Vitae suscipit tellus mauris "
-      "a diam maecenas sed. Lectus arcu bibendum at varius vel pharetra. "
-      "Dignissim sodales ut eu sem integer vitae justo. Id cursus metus "
-      "aliquam eleifend mi.";
-  Client << Text;
-  Client.flush();
+  std::string String(Bytes, 8);
 
-  llvm::Expected<std::string> MaybeText = Server.readFromSocket();
-  ASSERT_THAT_EXPECTED(MaybeText, llvm::Succeeded());
-  ASSERT_EQ(Text, *MaybeText);
+  ASSERT_EQ(8, *MaybeBytesRead);
+  ASSERT_EQ("01234567", String);
 }
 
 TEST(raw_socket_streamTest, READ_WITH_TIMEOUT) {
@@ -146,8 +92,9 @@ TEST(raw_socket_streamTest, READ_WITH_TIMEOUT) {
   ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded());
   raw_socket_stream &Server = **MaybeServer;
 
-  llvm::Expected<std::string> MaybeBytesRead =
-      Server.readFromSocket(std::chrono::milliseconds(100));
+  char Bytes[8];
+  llvm::Expected<ssize_t> MaybeBytesRead =
+      Server.read(Bytes, 8, std::chrono::milliseconds(100));
   ASSERT_EQ(llvm::errorToErrorCode(MaybeBytesRead.takeError()),
             std::errc::timed_out);
 }



More information about the llvm-commits mailing list