Skip to content

Commit 3db6bad

Browse files
committed
[lldb] Adding file and pipe support to lldb_private::MainLoopWindows.
This updates MainLoopWindows to support events for reading from a file and a socket type. This unifies both handle types using WaitForMultipleEvents which can listen to both sockets and files for change events. This should allow us to unify how we handle watching files/pipes/sockets on Windows and Posix systems.
1 parent 8763d29 commit 3db6bad

File tree

11 files changed

+188
-73
lines changed

11 files changed

+188
-73
lines changed

lldb/include/lldb/Host/File.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class File : public IOObject {
127127
/// \return
128128
/// a valid handle or IOObject::kInvalidHandleValue
129129
WaitableHandle GetWaitableHandle() override;
130+
bool HasReadableData() override;
130131

131132
/// Get the file specification for this file, if possible.
132133
///
@@ -400,6 +401,7 @@ class NativeFile : public File {
400401
Status Write(const void *buf, size_t &num_bytes) override;
401402
Status Close() override;
402403
WaitableHandle GetWaitableHandle() override;
404+
bool HasReadableData() override;
403405
Status GetFileSpec(FileSpec &file_spec) const override;
404406
int GetDescriptor() const override;
405407
FILE *GetStream() override;

lldb/include/lldb/Host/Socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class Socket : public IOObject {
158158

159159
bool IsValid() const override { return m_socket != kInvalidSocketValue; }
160160
WaitableHandle GetWaitableHandle() override;
161+
bool HasReadableData() override;
161162

162163
static llvm::Expected<HostAndPort>
163164
DecodeHostAndPort(llvm::StringRef host_and_port);
@@ -185,6 +186,7 @@ class Socket : public IOObject {
185186

186187
SocketProtocol m_protocol;
187188
NativeSocket m_socket;
189+
WaitableHandle m_waitable_handle;
188190
bool m_should_close_fd;
189191
};
190192

lldb/include/lldb/Host/windows/MainLoopWindows.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,10 @@ class MainLoopWindows : public MainLoopBase {
3737
void Interrupt() override;
3838

3939
private:
40-
void ProcessReadObject(IOObject::WaitableHandle handle);
4140
llvm::Expected<size_t> Poll();
4241

4342
struct FdInfo {
44-
void *event;
43+
lldb::IOObjectSP object_sp;
4544
Callback callback;
4645
};
4746
llvm::DenseMap<IOObject::WaitableHandle, FdInfo> m_read_fds;

lldb/include/lldb/Utility/IOObject.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <sys/types.h>
1515

1616
#include "lldb/lldb-private.h"
17+
#include "lldb/lldb-types.h"
1718

1819
namespace lldb_private {
1920

@@ -24,9 +25,9 @@ class IOObject {
2425
eFDTypeSocket, // Socket requiring send/recv
2526
};
2627

27-
// TODO: On Windows this should be a HANDLE, and wait should use
28-
// WaitForMultipleObjects
29-
typedef int WaitableHandle;
28+
// A handle for integrating with the host event loop model.
29+
using WaitableHandle = lldb::file_t;
30+
3031
static const WaitableHandle kInvalidHandleValue;
3132

3233
IOObject(FDType type) : m_fd_type(type) {}
@@ -40,6 +41,7 @@ class IOObject {
4041
FDType GetFdType() const { return m_fd_type; }
4142

4243
virtual WaitableHandle GetWaitableHandle() = 0;
44+
virtual bool HasReadableData() = 0;
4345

4446
protected:
4547
FDType m_fd_type;

lldb/source/Host/common/File.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ IOObject::WaitableHandle File::GetWaitableHandle() {
118118
return IOObject::kInvalidHandleValue;
119119
}
120120

121+
bool File::HasReadableData() { return false; }
122+
121123
Status File::GetFileSpec(FileSpec &file_spec) const {
122124
file_spec.Clear();
123125
return std::error_code(ENOTSUP, std::system_category());
@@ -274,7 +276,23 @@ int NativeFile::GetDescriptor() const {
274276
}
275277

276278
IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
279+
#ifdef _WIN32
280+
return (HANDLE)_get_osfhandle(GetDescriptor());
281+
#else
277282
return GetDescriptor();
283+
#endif
284+
}
285+
286+
bool NativeFile::HasReadableData() {
287+
#ifdef _WIN32
288+
DWORD available_bytes = 0;
289+
return !PeekNamedPipe((HANDLE)_get_osfhandle(GetDescriptor()), NULL, 0, NULL,
290+
&available_bytes, NULL) ||
291+
available_bytes > 0;
292+
#else
293+
size_t buffer_size = 0;
294+
return ioctl(GetDescriptor(), FIONREAD, buffer_size) != -1 && buffer_size > 0;
295+
#endif
278296
}
279297

280298
FILE *NativeFile::GetStream() {

lldb/source/Host/common/Socket.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@
3131
#include <netdb.h>
3232
#include <netinet/in.h>
3333
#include <netinet/tcp.h>
34+
#include <sys/ioctl.h>
3435
#include <sys/socket.h>
36+
#include <sys/stat.h>
3537
#include <sys/un.h>
38+
#include <termios.h>
3639
#include <unistd.h>
3740
#endif
3841

@@ -169,7 +172,9 @@ bool Socket::FindProtocolByScheme(const char *scheme,
169172

170173
Socket::Socket(SocketProtocol protocol, bool should_close)
171174
: IOObject(eFDTypeSocket), m_protocol(protocol),
172-
m_socket(kInvalidSocketValue), m_should_close_fd(should_close) {}
175+
m_socket(kInvalidSocketValue),
176+
m_waitable_handle(IOObject::kInvalidHandleValue),
177+
m_should_close_fd(should_close) {}
173178

174179
Socket::~Socket() { Close(); }
175180

@@ -313,8 +318,39 @@ Socket::DecodeHostAndPort(llvm::StringRef host_and_port) {
313318
}
314319

315320
IOObject::WaitableHandle Socket::GetWaitableHandle() {
316-
// TODO: On Windows, use WSAEventSelect
321+
#ifdef _WIN32
322+
if (m_socket == kInvalidSocketValue)
323+
return kInvalidHandleValue;
324+
325+
if (m_waitable_handle == kInvalidHandleValue) {
326+
m_waitable_handle = WSACreateEvent();
327+
assert(m_waitable_handle != WSA_INVALID_EVENT);
328+
if (WSAEventSelect(m_socket, m_waitable_handle,
329+
FD_ACCEPT | FD_READ | FD_WRITE) != 0)
330+
return kInvalidHandleValue;
331+
}
332+
333+
return m_waitable_handle;
334+
#else
317335
return m_socket;
336+
#endif
337+
}
338+
339+
bool Socket::HasReadableData() {
340+
#ifdef _WIN32
341+
if (!IsValid() || m_waitable_handle == kInvalidHandleValue)
342+
return false;
343+
344+
WSANETWORKEVENTS events;
345+
if (WSAEnumNetworkEvents(m_socket, m_waitable_handle, &events) != 0)
346+
return false;
347+
348+
return events.lNetworkEvents & FD_CLOSE ||
349+
events.lNetworkEvents & FD_ACCEPT || events.lNetworkEvents & FD_READ;
350+
#else
351+
size_t buffer_size = 0;
352+
return ioctl(m_socket, FIONREAD, buffer_size) != -1 && buffer_size > 0;
353+
#endif
318354
}
319355

320356
Status Socket::Read(void *buf, size_t &num_bytes) {
@@ -380,7 +416,14 @@ Status Socket::Close() {
380416
Log *log = GetLog(LLDBLog::Connection);
381417
LLDB_LOGF(log, "%p Socket::Close (fd = %" PRIu64 ")",
382418
static_cast<void *>(this), static_cast<uint64_t>(m_socket));
383-
419+
#ifdef _WIN32
420+
if (m_waitable_handle != kInvalidHandleValue) {
421+
if (WSACloseEvent(m_waitable_handle) == 0)
422+
m_waitable_handle = kInvalidHandleValue;
423+
else
424+
error = GetLastError();
425+
}
426+
#endif
384427
bool success = CloseSocket(m_socket) == 0;
385428
// A reference to a FD was passed in, set it to an invalid value
386429
m_socket = kInvalidSocketValue;

lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
276276
"%p ConnectionFileDescriptor::Read() fd = %" PRIu64
277277
", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
278278
static_cast<void *>(this),
279-
static_cast<uint64_t>(m_io_sp->GetWaitableHandle()),
279+
static_cast<file_t>(m_io_sp->GetWaitableHandle()),
280280
static_cast<void *>(dst), static_cast<uint64_t>(dst_len),
281281
static_cast<uint64_t>(bytes_read), error.AsCString());
282282
}
@@ -380,7 +380,7 @@ size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len,
380380
"%p ConnectionFileDescriptor::Write(fd = %" PRIu64
381381
", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
382382
static_cast<void *>(this),
383-
static_cast<uint64_t>(m_io_sp->GetWaitableHandle()),
383+
static_cast<file_t>(m_io_sp->GetWaitableHandle()),
384384
static_cast<const void *>(src), static_cast<uint64_t>(src_len),
385385
static_cast<uint64_t>(bytes_sent), error.AsCString());
386386
}
@@ -451,14 +451,17 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
451451
if (timeout)
452452
select_helper.SetTimeout(*timeout);
453453

454-
select_helper.FDSetRead(handle);
454+
// FIXME: Migrate to MainLoop.
455455
#if defined(_WIN32)
456+
if (const auto *sock = static_cast<Socket *>(m_io_sp.get()))
457+
select_helper.FDSetRead((socket_t)sock->GetNativeSocket());
456458
// select() won't accept pipes on Windows. The entire Windows codepath
457459
// needs to be converted over to using WaitForMultipleObjects and event
458460
// HANDLEs, but for now at least this will allow ::select() to not return
459461
// an error.
460462
const bool have_pipe_fd = false;
461463
#else
464+
select_helper.FDSetRead(handle);
462465
const bool have_pipe_fd = pipe_fd >= 0;
463466
#endif
464467
if (have_pipe_fd)
@@ -493,7 +496,12 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
493496
break; // Lets keep reading to until we timeout
494497
}
495498
} else {
499+
#if defined(_WIN32)
500+
if (const auto *sock = static_cast<Socket *>(m_io_sp.get());
501+
select_helper.FDIsSetRead(sock->GetNativeSocket()))
502+
#else
496503
if (select_helper.FDIsSetRead(handle))
504+
#endif
497505
return eConnectionStatusSuccess;
498506

499507
if (select_helper.FDIsSetRead(pipe_fd)) {

0 commit comments

Comments
 (0)