Skip to content

[lldb] Add a MainLoop version of DomainSocket::Accept #108188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 13, 2024
Merged

Conversation

labath
Copy link
Collaborator

@labath labath commented Sep 11, 2024

To go along with the existing TCPSocket implementation.

To go along with the existing TCPSocket implementation.
@llvmbot
Copy link
Member

llvmbot commented Sep 11, 2024

@llvm/pr-subscribers-lldb

Author: Pavel Labath (labath)

Changes

To go along with the existing TCPSocket implementation.


Full diff: https://github.com/llvm/llvm-project/pull/108188.diff

9 Files Affected:

  • (modified) lldb/include/lldb/Host/Socket.h (+12-1)
  • (modified) lldb/include/lldb/Host/common/TCPSocket.h (+2-8)
  • (modified) lldb/include/lldb/Host/common/UDPSocket.h (+7-1)
  • (modified) lldb/include/lldb/Host/posix/DomainSocket.h (+7-1)
  • (modified) lldb/source/Host/common/Socket.cpp (+14)
  • (modified) lldb/source/Host/common/TCPSocket.cpp (+3-16)
  • (modified) lldb/source/Host/common/UDPSocket.cpp (-4)
  • (modified) lldb/source/Host/posix/DomainSocket.cpp (+34-8)
  • (modified) lldb/unittests/Host/SocketTest.cpp (+38-2)
diff --git a/lldb/include/lldb/Host/Socket.h b/lldb/include/lldb/Host/Socket.h
index 764a048976eb41..14468c98ac5a3a 100644
--- a/lldb/include/lldb/Host/Socket.h
+++ b/lldb/include/lldb/Host/Socket.h
@@ -12,6 +12,7 @@
 #include <memory>
 #include <string>
 
+#include "lldb/Host/MainLoopBase.h"
 #include "lldb/lldb-private.h"
 
 #include "lldb/Host/SocketAddress.h"
@@ -97,7 +98,17 @@ class Socket : public IOObject {
 
   virtual Status Connect(llvm::StringRef name) = 0;
   virtual Status Listen(llvm::StringRef name, int backlog) = 0;
-  virtual Status Accept(Socket *&socket) = 0;
+
+  // Use the provided main loop instance to accept new connections. The callback
+  // will be called (from MainLoop::Run) for each new connection. This function
+  // does not block.
+  virtual llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
+  Accept(MainLoopBase &loop,
+         std::function<void(std::unique_ptr<Socket> socket)> sock_cb) = 0;
+
+  // Accept a single connection and "return" it in the pointer argument. This
+  // function blocks until the connection arrives.
+  virtual Status Accept(Socket *&socket);
 
   // Initialize a Tcp Socket object in listening mode.  listen and accept are
   // implemented separately because the caller may wish to manipulate or query
diff --git a/lldb/include/lldb/Host/common/TCPSocket.h b/lldb/include/lldb/Host/common/TCPSocket.h
index 78e80568e39967..eefe0240fe4a95 100644
--- a/lldb/include/lldb/Host/common/TCPSocket.h
+++ b/lldb/include/lldb/Host/common/TCPSocket.h
@@ -42,16 +42,10 @@ class TCPSocket : public Socket {
   Status Connect(llvm::StringRef name) override;
   Status Listen(llvm::StringRef name, int backlog) override;
 
-  // Use the provided main loop instance to accept new connections. The callback
-  // will be called (from MainLoop::Run) for each new connection. This function
-  // does not block.
+  using Socket::Accept;
   llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
   Accept(MainLoopBase &loop,
-         std::function<void(std::unique_ptr<TCPSocket> socket)> sock_cb);
-
-  // Accept a single connection and "return" it in the pointer argument. This
-  // function blocks until the connection arrives.
-  Status Accept(Socket *&conn_socket) override;
+         std::function<void(std::unique_ptr<Socket> socket)> sock_cb) override;
 
   Status CreateSocket(int domain);
 
diff --git a/lldb/include/lldb/Host/common/UDPSocket.h b/lldb/include/lldb/Host/common/UDPSocket.h
index bae707e345d87c..7348010d02ada2 100644
--- a/lldb/include/lldb/Host/common/UDPSocket.h
+++ b/lldb/include/lldb/Host/common/UDPSocket.h
@@ -27,7 +27,13 @@ class UDPSocket : public Socket {
   size_t Send(const void *buf, const size_t num_bytes) override;
   Status Connect(llvm::StringRef name) override;
   Status Listen(llvm::StringRef name, int backlog) override;
-  Status Accept(Socket *&socket) override;
+
+  llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
+  Accept(MainLoopBase &loop,
+         std::function<void(std::unique_ptr<Socket> socket)> sock_cb) override {
+    return llvm::errorCodeToError(
+        std::make_error_code(std::errc::operation_not_supported));
+  }
 
   SocketAddress m_sockaddr;
 };
diff --git a/lldb/include/lldb/Host/posix/DomainSocket.h b/lldb/include/lldb/Host/posix/DomainSocket.h
index 35c33811f60de6..983f43bd633719 100644
--- a/lldb/include/lldb/Host/posix/DomainSocket.h
+++ b/lldb/include/lldb/Host/posix/DomainSocket.h
@@ -14,11 +14,17 @@
 namespace lldb_private {
 class DomainSocket : public Socket {
 public:
+  DomainSocket(NativeSocket socket, bool should_close,
+               bool child_processes_inherit);
   DomainSocket(bool should_close, bool child_processes_inherit);
 
   Status Connect(llvm::StringRef name) override;
   Status Listen(llvm::StringRef name, int backlog) override;
-  Status Accept(Socket *&socket) override;
+
+  using Socket::Accept;
+  llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
+  Accept(MainLoopBase &loop,
+         std::function<void(std::unique_ptr<Socket> socket)> sock_cb) override;
 
   std::string GetRemoteConnectionURI() const override;
 
diff --git a/lldb/source/Host/common/Socket.cpp b/lldb/source/Host/common/Socket.cpp
index 1a63571b94c6f1..d69eb608204033 100644
--- a/lldb/source/Host/common/Socket.cpp
+++ b/lldb/source/Host/common/Socket.cpp
@@ -10,6 +10,7 @@
 
 #include "lldb/Host/Config.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Host/MainLoop.h"
 #include "lldb/Host/SocketAddress.h"
 #include "lldb/Host/common/TCPSocket.h"
 #include "lldb/Host/common/UDPSocket.h"
@@ -459,6 +460,19 @@ NativeSocket Socket::CreateSocket(const int domain, const int type,
   return sock;
 }
 
+Status Socket::Accept(Socket *&socket) {
+  MainLoop accept_loop;
+  llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> expected_handles =
+      Accept(accept_loop,
+             [&accept_loop, &socket](std::unique_ptr<Socket> sock) {
+               socket = sock.release();
+               accept_loop.RequestTermination();
+             });
+  if (!expected_handles)
+    return Status::FromError(expected_handles.takeError());
+  return accept_loop.Run();
+}
+
 NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,
                                   socklen_t *addrlen,
                                   bool child_processes_inherit, Status &error) {
diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp
index b28ba148ee1afa..2d16b605af9497 100644
--- a/lldb/source/Host/common/TCPSocket.cpp
+++ b/lldb/source/Host/common/TCPSocket.cpp
@@ -232,9 +232,9 @@ void TCPSocket::CloseListenSockets() {
   m_listen_sockets.clear();
 }
 
-llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> TCPSocket::Accept(
-    MainLoopBase &loop,
-    std::function<void(std::unique_ptr<TCPSocket> socket)> sock_cb) {
+llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>>
+TCPSocket::Accept(MainLoopBase &loop,
+                  std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
   if (m_listen_sockets.size() == 0)
     return llvm::createStringError("No open listening sockets!");
 
@@ -278,19 +278,6 @@ llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> TCPSocket::Accept(
   return handles;
 }
 
-Status TCPSocket::Accept(Socket *&conn_socket) {
-  MainLoop accept_loop;
-  llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> expected_handles =
-      Accept(accept_loop,
-             [&accept_loop, &conn_socket](std::unique_ptr<TCPSocket> sock) {
-               conn_socket = sock.release();
-               accept_loop.RequestTermination();
-             });
-  if (!expected_handles)
-    return Status::FromError(expected_handles.takeError());
-  return accept_loop.Run();
-}
-
 int TCPSocket::SetOptionNoDelay() {
   return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
 }
diff --git a/lldb/source/Host/common/UDPSocket.cpp b/lldb/source/Host/common/UDPSocket.cpp
index 2a7a6cff414b14..05d7b2e6506027 100644
--- a/lldb/source/Host/common/UDPSocket.cpp
+++ b/lldb/source/Host/common/UDPSocket.cpp
@@ -47,10 +47,6 @@ Status UDPSocket::Listen(llvm::StringRef name, int backlog) {
   return Status::FromErrorStringWithFormat("%s", g_not_supported_error);
 }
 
-Status UDPSocket::Accept(Socket *&socket) {
-  return Status::FromErrorStringWithFormat("%s", g_not_supported_error);
-}
-
 llvm::Expected<std::unique_ptr<UDPSocket>>
 UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit) {
   std::unique_ptr<UDPSocket> socket;
diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp
index 2d18995c3bb469..369123f2239302 100644
--- a/lldb/source/Host/posix/DomainSocket.cpp
+++ b/lldb/source/Host/posix/DomainSocket.cpp
@@ -7,11 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/posix/DomainSocket.h"
+#include "lldb/Utility/LLDBLog.h"
 
 #include "llvm/Support/Errno.h"
 #include "llvm/Support/FileSystem.h"
 
 #include <cstddef>
+#include <memory>
 #include <sys/socket.h>
 #include <sys/un.h>
 
@@ -57,7 +59,14 @@ static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
 }
 
 DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit)
-    : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {}
+    : DomainSocket(kInvalidSocketValue, should_close, child_processes_inherit) {
+}
+
+DomainSocket::DomainSocket(NativeSocket socket, bool should_close,
+                           bool child_processes_inherit)
+    : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {
+  m_socket = socket;
+}
 
 DomainSocket::DomainSocket(SocketProtocol protocol,
                            bool child_processes_inherit)
@@ -108,14 +117,31 @@ Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
   return error;
 }
 
-Status DomainSocket::Accept(Socket *&socket) {
-  Status error;
-  auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr,
-                              m_child_processes_inherit, error);
-  if (error.Success())
-    socket = new DomainSocket(conn_fd, *this);
+llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> DomainSocket::Accept(
+    MainLoopBase &loop,
+    std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
+  // TODO: Refactor MainLoop to avoid the shared_ptr requirement.
+  auto io_sp = std::make_shared<DomainSocket>(GetNativeSocket(), false,
+                                              m_child_processes_inherit);
+  auto cb = [this, sock_cb](MainLoopBase &loop) {
+    Log *log = GetLog(LLDBLog::Host);
+    Status error;
+    auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr,
+                                m_child_processes_inherit, error);
+    if (error.Fail()) {
+      LLDB_LOG(log, "AcceptSocket({0}): {1}", GetNativeSocket(), error);
+      return;
+    }
+    std::unique_ptr<DomainSocket> sock_up(new DomainSocket(conn_fd, *this));
+    sock_cb(std::move(sock_up));
+  };
 
-  return error;
+  Status error;
+  std::vector<MainLoopBase::ReadHandleUP> handles;
+  handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
+  if (error.Fail())
+    return error.ToError();
+  return handles;
 }
 
 size_t DomainSocket::GetNameOffset() const { return 0; }
diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp
index 3a356d11ba1a51..a93b928e274d03 100644
--- a/lldb/unittests/Host/SocketTest.cpp
+++ b/lldb/unittests/Host/SocketTest.cpp
@@ -85,6 +85,42 @@ TEST_P(SocketTest, DomainListenConnectAccept) {
   std::unique_ptr<DomainSocket> socket_b_up;
   CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up);
 }
+
+TEST_P(SocketTest, DomainMainLoopAccept) {
+  llvm::SmallString<64> Path;
+  std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
+  ASSERT_FALSE(EC);
+  llvm::sys::path::append(Path, "test");
+
+  // Skip the test if the $TMPDIR is too long to hold a domain socket.
+  if (Path.size() > 107u)
+    return;
+
+  auto listen_socket_up = std::make_unique<DomainSocket>(
+      /*should_close=*/true, /*child_process_inherit=*/false);
+  Status error = listen_socket_up->Listen(Path, 5);
+  ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
+  ASSERT_TRUE(listen_socket_up->IsValid());
+
+  MainLoop loop;
+  std::unique_ptr<Socket> accepted_socket_up;
+  auto expected_handles = listen_socket_up->Accept(
+      loop, [&accepted_socket_up, &loop](std::unique_ptr<Socket> sock_up) {
+        accepted_socket_up = std::move(sock_up);
+        loop.RequestTermination();
+      });
+  ASSERT_THAT_EXPECTED(expected_handles, llvm::Succeeded());
+
+  auto connect_socket_up = std::make_unique<DomainSocket>(
+      /*should_close=*/true, /*child_process_inherit=*/false);
+  ASSERT_THAT_ERROR(connect_socket_up->Connect(Path).ToError(),
+                    llvm::Succeeded());
+  ASSERT_TRUE(connect_socket_up->IsValid());
+
+  loop.Run();
+  ASSERT_TRUE(accepted_socket_up);
+  ASSERT_TRUE(accepted_socket_up->IsValid());
+}
 #endif
 
 TEST_P(SocketTest, TCPListen0ConnectAccept) {
@@ -109,9 +145,9 @@ TEST_P(SocketTest, TCPMainLoopAccept) {
   ASSERT_TRUE(listen_socket_up->IsValid());
 
   MainLoop loop;
-  std::unique_ptr<TCPSocket> accepted_socket_up;
+  std::unique_ptr<Socket> accepted_socket_up;
   auto expected_handles = listen_socket_up->Accept(
-      loop, [&accepted_socket_up, &loop](std::unique_ptr<TCPSocket> sock_up) {
+      loop, [&accepted_socket_up, &loop](std::unique_ptr<Socket> sock_up) {
         accepted_socket_up = std::move(sock_up);
         loop.RequestTermination();
       });

Copy link

github-actions bot commented Sep 11, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@slydiman slydiman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but fix the test please.

@@ -85,6 +85,43 @@ TEST_P(SocketTest, DomainListenConnectAccept) {
std::unique_ptr<DomainSocket> socket_b_up;
CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up);
}

TEST_P(SocketTest, DomainMainLoopAccept) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add #if LLDB_ENABLE_POSIX. Otherwise it will fail on Windows.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already in a ifdef block, next to the other domain socket test. That's why you don't see an ifdef in the default view.

@labath labath merged commit ebbc9ed into llvm:main Sep 13, 2024
7 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 13, 2024

LLVM Buildbot has detected a new failure on builder lldb-x86_64-debian running on lldb-x86_64-debian while building lldb at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/162/builds/6215

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: functionalities/breakpoint/breakpoint_callback_command_source/TestBreakpointCallbackCommandSource.py (21 of 2682)
PASS: lldb-api :: iohandler/stdio/TestIOHandlerProcessSTDIO.py (22 of 2682)
PASS: lldb-api :: iohandler/completion/TestIOHandlerCompletion.py (23 of 2682)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteThreadsInStopReply.py (24 of 2682)
PASS: lldb-api :: iohandler/sigint/TestProcessIOHandlerInterrupt.py (25 of 2682)
PASS: lldb-api :: commands/expression/multiline-completion/TestMultilineCompletion.py (26 of 2682)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteExpeditedRegisters.py (27 of 2682)
PASS: lldb-api :: tools/lldb-server/vCont-threads/TestSignal.py (28 of 2682)
PASS: lldb-api :: tools/lldb-dap/variables/TestDAP_variables.py (29 of 2682)
PASS: lldb-api :: functionalities/load_unload/TestLoadUnload.py (30 of 2682)
FAIL: lldb-api :: tools/lldb-dap/launch/TestDAP_launch.py (31 of 2682)
******************** TEST 'lldb-api :: tools/lldb-dap/launch/TestDAP_launch.py' FAILED ********************
Script:
--
/usr/bin/python3 /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env ARCHIVER=/usr/bin/ar --env OBJCOPY=/usr/bin/objcopy --env LLVM_LIBS_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/./lib --env LLVM_INCLUDE_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/include --env LLVM_TOOLS_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/./bin --arch x86_64 --build-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex --lldb-module-cache-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/lldb --compiler /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/clang --dsymutil /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/dsymutil --llvm-tools-dir /home/worker/2.0.1/lldb-x86_64-debian/build/./bin --lldb-obj-root /home/worker/2.0.1/lldb-x86_64-debian/build/tools/lldb --lldb-libs-dir /home/worker/2.0.1/lldb-x86_64-debian/build/./lib -t /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/tools/lldb-dap/launch -p TestDAP_launch.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 20.0.0git (https://github.com/llvm/llvm-project.git revision ebbc9ed2d60cacffc87232dc32374a2b38b92175)
  clang revision ebbc9ed2d60cacffc87232dc32374a2b38b92175
  llvm revision ebbc9ed2d60cacffc87232dc32374a2b38b92175
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']
========= DEBUG ADAPTER PROTOCOL LOGS =========
1726225186.522618532 --> 
Content-Length: 344

{
  "arguments": {
    "adapterID": "lldb-native",
    "clientID": "vscode",
    "columnsStartAt1": true,
    "linesStartAt1": true,
    "locale": "en-us",
    "pathFormat": "path",
    "sourceInitFile": false,
    "supportsRunInTerminalRequest": true,
    "supportsStartDebuggingRequest": true,
    "supportsVariablePaging": true,
    "supportsVariableType": true
  },
  "command": "initialize",
  "seq": 1,
  "type": "request"
}
1726225186.524738789 <-- 
Content-Length: 1556


slydiman added a commit to slydiman/llvm-project that referenced this pull request Sep 13, 2024
@labath labath deleted the unix branch November 8, 2024 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants