Skip to content

Commit 4a65ba8

Browse files
committed
[llvm][Support] Improvements to raw_socket_stream functionality and documentation
1 parent eb21ee4 commit 4a65ba8

File tree

3 files changed

+315
-78
lines changed

3 files changed

+315
-78
lines changed

llvm/include/llvm/Support/raw_socket_stream.h

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

4177
public:
42-
static Expected<ListeningSocket> createUnix(
78+
~ListeningSocket();
79+
ListeningSocket(ListeningSocket &&LS);
80+
ListeningSocket(const ListeningSocket &LS) = delete;
81+
ListeningSocket &operator=(const ListeningSocket &) = delete;
82+
83+
/// Closes the FD, unlinks the socket file, and writes to PipeFD.
84+
///
85+
/// After the construction of the ListeningSocket, shutdown is signal safe if
86+
/// it is called during the lifetime of the object. shutdown can be called
87+
/// concurrently with ListeningSocket::accept as writing to PipeFD will cause
88+
/// a blocking call to ::poll to return.
89+
///
90+
/// Once shutdown is called there is no way to reinitialize ListeningSocket.
91+
void shutdown();
92+
93+
/// Accepts an incoming connection on the listening socket. This method can
94+
/// optionally either block until a connection is available or timeout after a
95+
/// specified amount of time has passed. By default the method will block
96+
/// until the socket has recieved a connection.
97+
///
98+
/// \param Timeout An optional timeout duration in milliseconds
99+
///
100+
Expected<std::unique_ptr<raw_socket_stream>>
101+
accept(std::optional<std::chrono::milliseconds> Timeout = std::nullopt);
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+
///
110+
static Expected<ListeningSocket> createListeningUnixSocket(
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,10 +124,10 @@ 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>>
60-
createConnectedUnix(StringRef SocketPath);
130+
createConnectedUnixSocket(StringRef SocketPath);
61131
~raw_socket_stream();
62132
};
63133

0 commit comments

Comments
 (0)