Skip to content

Commit 87e6f87

Browse files
cpsughrueBigcheese
andauthored
[llvm][Support] Improvements to ListeningSocket functionality and documentation (#84710)
Improvements include * Enable `ListeningSocket::accept` to timeout after a specified amount of time or block indefinitely * Enable `ListeningSocket::createUnix` to handle instances where the target socket address already exists and differentiate between situations where the existing file does and does not already have a bound socket * Doxygen comments Functionality added for the module build daemon --------- Co-authored-by: Michael Spencer <[email protected]>
1 parent 289a2c3 commit 87e6f87

File tree

3 files changed

+339
-73
lines changed

3 files changed

+339
-73
lines changed

llvm/include/llvm/Support/raw_socket_stream.h

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,105 @@
1717
#include "llvm/Support/Threading.h"
1818
#include "llvm/Support/raw_ostream.h"
1919

20+
#include <atomic>
21+
#include <chrono>
22+
2023
namespace llvm {
2124

2225
class raw_socket_stream;
2326

24-
// Make sure that calls to WSAStartup and WSACleanup are balanced.
2527
#ifdef _WIN32
28+
/// Ensures proper initialization and cleanup of winsock resources
29+
///
30+
/// Make sure that calls to WSAStartup and WSACleanup are balanced.
2631
class WSABalancer {
2732
public:
2833
WSABalancer();
2934
~WSABalancer();
3035
};
3136
#endif // _WIN32
3237

38+
/// Manages a passive (i.e., listening) UNIX domain socket
39+
///
40+
/// The ListeningSocket class encapsulates a UNIX domain socket that can listen
41+
/// and accept incoming connections. ListeningSocket is portable and supports
42+
/// Windows builds begining with Insider Build 17063. ListeningSocket is
43+
/// designed for server-side operations, working alongside \p raw_socket_streams
44+
/// that function as client connections.
45+
///
46+
/// Usage example:
47+
/// \code{.cpp}
48+
/// std::string Path = "/path/to/socket"
49+
/// Expected<ListeningSocket> S = ListeningSocket::createUnix(Path);
50+
///
51+
/// if (S) {
52+
/// Expected<std::unique_ptr<raw_socket_stream>> connection = S->accept();
53+
/// if (connection) {
54+
/// // Use the accepted raw_socket_stream for communication.
55+
/// }
56+
/// }
57+
/// \endcode
58+
///
3359
class ListeningSocket {
34-
int FD;
35-
std::string SocketPath;
36-
ListeningSocket(int SocketFD, StringRef SocketPath);
60+
61+
std::atomic<int> FD;
62+
std::string SocketPath; // Not modified after construction
63+
64+
/// If a seperate thread calls ListeningSocket::shutdown, the ListeningSocket
65+
/// file descriptor (FD) could be closed while ::poll is waiting for it to be
66+
/// ready to perform a I/O operations. ::poll will continue to block even
67+
/// after FD is closed so use a self-pipe mechanism to get ::poll to return
68+
int PipeFD[2]; // Not modified after construction other then move constructor
69+
70+
ListeningSocket(int SocketFD, StringRef SocketPath, int PipeFD[2]);
71+
3772
#ifdef _WIN32
3873
WSABalancer _;
3974
#endif // _WIN32
4075

4176
public:
77+
~ListeningSocket();
78+
ListeningSocket(ListeningSocket &&LS);
79+
ListeningSocket(const ListeningSocket &LS) = delete;
80+
ListeningSocket &operator=(const ListeningSocket &) = delete;
81+
82+
/// Closes the FD, unlinks the socket file, and writes to PipeFD.
83+
///
84+
/// After the construction of the ListeningSocket, shutdown is signal safe if
85+
/// it is called during the lifetime of the object. shutdown can be called
86+
/// concurrently with ListeningSocket::accept as writing to PipeFD will cause
87+
/// a blocking call to ::poll to return.
88+
///
89+
/// Once shutdown is called there is no way to reinitialize ListeningSocket.
90+
void shutdown();
91+
92+
/// Accepts an incoming connection on the listening socket. This method can
93+
/// optionally either block until a connection is available or timeout after a
94+
/// specified amount of time has passed. By default the method will block
95+
/// until the socket has recieved a connection.
96+
///
97+
/// \param Timeout An optional timeout duration in milliseconds. Setting
98+
/// Timeout to -1 causes accept to block indefinitely
99+
///
100+
Expected<std::unique_ptr<raw_socket_stream>>
101+
accept(std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1));
102+
103+
/// Creates a listening socket bound to the specified file system path.
104+
/// Handles the socket creation, binding, and immediately starts listening for
105+
/// incoming connections.
106+
///
107+
/// \param SocketPath The file system path where the socket will be created
108+
/// \param MaxBacklog The max number of connections in a socket's backlog
109+
///
42110
static Expected<ListeningSocket> createUnix(
43111
StringRef SocketPath,
44112
int MaxBacklog = llvm::hardware_concurrency().compute_thread_count());
45-
Expected<std::unique_ptr<raw_socket_stream>> accept();
46-
ListeningSocket(ListeningSocket &&LS);
47-
~ListeningSocket();
48113
};
114+
115+
//===----------------------------------------------------------------------===//
116+
// raw_socket_stream
117+
//===----------------------------------------------------------------------===//
118+
49119
class raw_socket_stream : public raw_fd_stream {
50120
uint64_t current_pos() const override { return 0; }
51121
#ifdef _WIN32
@@ -54,7 +124,7 @@ class raw_socket_stream : public raw_fd_stream {
54124

55125
public:
56126
raw_socket_stream(int SocketFD);
57-
/// Create a \p raw_socket_stream connected to the Unix domain socket at \p
127+
/// Create a \p raw_socket_stream connected to the UNIX domain socket at \p
58128
/// SocketPath.
59129
static Expected<std::unique_ptr<raw_socket_stream>>
60130
createConnectedUnix(StringRef SocketPath);

0 commit comments

Comments
 (0)