Skip to content

Commit 0723870

Browse files
authored
[lldb] Add timeout argument to Socket::Accept (#117691)
Allows us to stop waiting for a connection if it doesn't come in a certain amount of time. Right now, I'm keeping the status quo (infitnite wait) in the "production" code, but using smaller (finite) values in tests. (A lot of these tests create "loopback" connections, where a really short wait is sufficient: on linux at least even a poll (0s wait) is sufficient if the other end has connect()ed already, but this doesn't seem to be the case on Windows, so I'm using a 1s wait in these cases).
1 parent 4dfa021 commit 0723870

File tree

8 files changed

+62
-27
lines changed

8 files changed

+62
-27
lines changed

lldb/include/lldb/Host/Socket.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <string>
1414

1515
#include "lldb/Host/MainLoopBase.h"
16+
#include "lldb/Utility/Timeout.h"
1617
#include "lldb/lldb-private.h"
1718

1819
#include "lldb/Host/SocketAddress.h"
@@ -108,7 +109,7 @@ class Socket : public IOObject {
108109

109110
// Accept a single connection and "return" it in the pointer argument. This
110111
// function blocks until the connection arrives.
111-
virtual Status Accept(Socket *&socket);
112+
virtual Status Accept(const Timeout<std::micro> &timeout, Socket *&socket);
112113

113114
// Initialize a Tcp Socket object in listening mode. listen and accept are
114115
// implemented separately because the caller may wish to manipulate or query

lldb/source/Host/common/Socket.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@ NativeSocket Socket::CreateSocket(const int domain, const int type,
460460
return sock;
461461
}
462462

463-
Status Socket::Accept(Socket *&socket) {
463+
Status Socket::Accept(const Timeout<std::micro> &timeout, Socket *&socket) {
464+
socket = nullptr;
464465
MainLoop accept_loop;
465466
llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> expected_handles =
466467
Accept(accept_loop,
@@ -470,7 +471,15 @@ Status Socket::Accept(Socket *&socket) {
470471
});
471472
if (!expected_handles)
472473
return Status::FromError(expected_handles.takeError());
473-
return accept_loop.Run();
474+
if (timeout) {
475+
accept_loop.AddCallback(
476+
[](MainLoopBase &loop) { loop.RequestTermination(); }, *timeout);
477+
}
478+
if (Status status = accept_loop.Run(); status.Fail())
479+
return status;
480+
if (socket)
481+
return Status();
482+
return Status(std::make_error_code(std::errc::timed_out));
474483
}
475484

476485
NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,

lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ lldb::ConnectionStatus ConnectionFileDescriptor::AcceptSocket(
543543

544544
if (!error.Fail()) {
545545
post_listen_callback(*listening_socket);
546-
error = listening_socket->Accept(accepted_socket);
546+
error = listening_socket->Accept(/*timeout=*/std::nullopt, accepted_socket);
547547
}
548548

549549
if (!error.Fail()) {

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,10 +1223,6 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
12231223
listen_socket.Listen("localhost:0", backlog).ToError())
12241224
return error;
12251225

1226-
Socket *accept_socket = nullptr;
1227-
std::future<Status> accept_status = std::async(
1228-
std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
1229-
12301226
llvm::SmallString<32> remote_addr;
12311227
llvm::raw_svector_ostream(remote_addr)
12321228
<< "connect://localhost:" << listen_socket.GetLocalPortNumber();
@@ -1238,10 +1234,15 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
12381234
return llvm::createStringError(llvm::inconvertibleErrorCode(),
12391235
"Unable to connect: %s", status.AsCString());
12401236

1241-
client.SetConnection(std::move(conn_up));
1242-
if (llvm::Error error = accept_status.get().ToError())
1243-
return error;
1237+
// The connection was already established above, so a short timeout is
1238+
// sufficient.
1239+
Socket *accept_socket = nullptr;
1240+
if (Status accept_status =
1241+
listen_socket.Accept(std::chrono::seconds(1), accept_socket);
1242+
accept_status.Fail())
1243+
return accept_status.takeError();
12441244

1245+
client.SetConnection(std::move(conn_up));
12451246
server.SetConnection(
12461247
std::make_unique<ConnectionFileDescriptor>(accept_socket));
12471248
return llvm::Error::success();

lldb/unittests/Host/MainLoopTest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class MainLoopTest : public testing::Test {
4242
llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber())
4343
.str());
4444
ASSERT_TRUE(error.Success());
45-
ASSERT_TRUE(listen_socket_up->Accept(accept_socket).Success());
45+
ASSERT_TRUE(listen_socket_up->Accept(std::chrono::seconds(1), accept_socket)
46+
.Success());
4647

4748
callback_count = 0;
4849
socketpair[0] = std::move(connect_socket_up);

lldb/unittests/Host/SocketTest.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
#include "lldb/Host/MainLoop.h"
1313
#include "lldb/Utility/UriParser.h"
1414
#include "llvm/Testing/Support/Error.h"
15+
#include "gmock/gmock.h"
1516
#include "gtest/gtest.h"
17+
#include <chrono>
1618

1719
using namespace lldb_private;
1820

@@ -133,6 +135,27 @@ TEST_P(SocketTest, TCPListen0ConnectAccept) {
133135
&socket_b_up);
134136
}
135137

138+
TEST_P(SocketTest, TCPAcceptTimeout) {
139+
if (!HostSupportsProtocol())
140+
return;
141+
142+
const bool child_processes_inherit = false;
143+
auto listen_socket_up =
144+
std::make_unique<TCPSocket>(true, child_processes_inherit);
145+
Status error = listen_socket_up->Listen(
146+
llvm::formatv("[{0}]:0", GetParam().localhost_ip).str(), 5);
147+
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
148+
ASSERT_TRUE(listen_socket_up->IsValid());
149+
150+
Socket *socket;
151+
ASSERT_THAT_ERROR(
152+
listen_socket_up->Accept(std::chrono::milliseconds(10), socket)
153+
.takeError(),
154+
llvm::Failed<llvm::ErrorInfoBase>(
155+
testing::Property(&llvm::ErrorInfoBase::convertToErrorCode,
156+
std::make_error_code(std::errc::timed_out))));
157+
}
158+
136159
TEST_P(SocketTest, TCPMainLoopAccept) {
137160
if (!HostSupportsProtocol())
138161
return;

lldb/unittests/TestingSupport/Host/SocketTestUtilities.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919

2020
using namespace lldb_private;
2121

22-
static void AcceptThread(Socket *listen_socket, bool child_processes_inherit,
23-
Socket **accept_socket, Status *error) {
24-
*error = listen_socket->Accept(*accept_socket);
25-
}
26-
2722
template <typename SocketType>
2823
void lldb_private::CreateConnectedSockets(
2924
llvm::StringRef listen_remote_address,
@@ -38,12 +33,6 @@ void lldb_private::CreateConnectedSockets(
3833
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
3934
ASSERT_TRUE(listen_socket_up->IsValid());
4035

41-
Status accept_error;
42-
Socket *accept_socket;
43-
std::thread accept_thread(AcceptThread, listen_socket_up.get(),
44-
child_processes_inherit, &accept_socket,
45-
&accept_error);
46-
4736
std::string connect_remote_address = get_connect_addr(*listen_socket_up);
4837
std::unique_ptr<SocketType> connect_socket_up(
4938
new SocketType(true, child_processes_inherit));
@@ -55,9 +44,13 @@ void lldb_private::CreateConnectedSockets(
5544
a_up->swap(connect_socket_up);
5645
ASSERT_TRUE((*a_up)->IsValid());
5746

58-
accept_thread.join();
47+
Socket *accept_socket;
48+
ASSERT_THAT_ERROR(
49+
listen_socket_up->Accept(std::chrono::seconds(1), accept_socket)
50+
.takeError(),
51+
llvm::Succeeded());
52+
5953
b_up->reset(static_cast<SocketType *>(accept_socket));
60-
ASSERT_THAT_ERROR(accept_error.ToError(), llvm::Succeeded());
6154
ASSERT_NE(nullptr, b_up->get());
6255
ASSERT_TRUE((*b_up)->IsValid());
6356

lldb/unittests/tools/lldb-server/tests/TestClient.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@ using namespace lldb_private;
2626
using namespace llvm;
2727
using namespace llgs_tests;
2828

29+
static std::chrono::seconds GetDefaultTimeout() {
30+
return std::chrono::seconds{10};
31+
}
32+
2933
TestClient::TestClient(std::unique_ptr<Connection> Conn) {
3034
SetConnection(std::move(Conn));
31-
SetPacketTimeout(std::chrono::seconds(10));
35+
SetPacketTimeout(GetDefaultTimeout());
3236
}
3337

3438
TestClient::~TestClient() {
@@ -117,7 +121,10 @@ TestClient::launchCustom(StringRef Log, bool disable_stdio,
117121
return status.ToError();
118122

119123
Socket *accept_socket;
120-
listen_socket.Accept(accept_socket);
124+
if (llvm::Error E =
125+
listen_socket.Accept(2 * GetDefaultTimeout(), accept_socket)
126+
.takeError())
127+
return E;
121128
auto Conn = std::make_unique<ConnectionFileDescriptor>(accept_socket);
122129
auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
123130

0 commit comments

Comments
 (0)