88
99#include " lldb/Host/windows/MainLoopWindows.h"
1010#include " lldb/Host/Config.h"
11+ #include " lldb/Host/Socket.h"
1112#include " lldb/Utility/Status.h"
1213#include " llvm/Config/llvm-config.h"
14+ #include " llvm/Support/Casting.h"
15+ #include " llvm/Support/WindowsError.h"
1316#include < algorithm>
1417#include < cassert>
1518#include < cerrno>
@@ -31,6 +34,122 @@ static DWORD ToTimeout(std::optional<MainLoopWindows::TimePoint> point) {
3134 return ceil<milliseconds>(dur).count ();
3235}
3336
37+ namespace {
38+
39+ class PipeEvent : public MainLoopWindows ::IOEvent {
40+ public:
41+ explicit PipeEvent (HANDLE handle)
42+ : IOEvent((IOObject::WaitableHandle)CreateEventW(
43+ NULL , /* bManualReset=*/ FALSE ,
44+ /* bInitialState=*/ FALSE , NULL )),
45+ m_handle(handle), m_ready(CreateEventW(NULL , /* bManualReset=*/ FALSE ,
46+ /* bInitialState=*/ FALSE , NULL )) {
47+ assert (m_event && m_ready);
48+ }
49+
50+ ~PipeEvent () override {
51+ if (m_monitor_thread.joinable ()) {
52+ m_stopped = true ;
53+ SetEvent (m_ready);
54+ // Keep trying to cancel ReadFile() until the thread exits.
55+ do {
56+ CancelIoEx ((HANDLE)m_handle, /* lpOverlapped=*/ NULL );
57+ } while (WaitForSingleObject (m_monitor_thread.native_handle (), 1 ) ==
58+ WAIT_TIMEOUT);
59+ m_monitor_thread.join ();
60+ }
61+ CloseHandle ((HANDLE)m_event);
62+ CloseHandle (m_ready);
63+ }
64+
65+ void WillPoll () override {
66+ if (!m_monitor_thread.joinable ())
67+ m_monitor_thread = std::thread (&PipeEvent::Monitor, this );
68+ }
69+
70+ void Disarm () override { SetEvent (m_ready); }
71+
72+ // / Monitors the handle performing a zero byte read to determine when data is
73+ // / avaiable.
74+ void Monitor () {
75+ do {
76+ char buf[1 ];
77+ DWORD bytes_read = 0 ;
78+ OVERLAPPED ov = {0 };
79+ // Block on a 0-byte read; this will only resume when data is
80+ // available in the pipe. The pipe must be PIPE_WAIT or this thread
81+ // will spin.
82+ BOOL success =
83+ ReadFile (m_handle, buf, /* nNumberOfBytesToRead=*/ 0 , &bytes_read, &ov);
84+ DWORD bytes_available = 0 ;
85+ DWORD err = GetLastError ();
86+ if (!success && err == ERROR_IO_PENDING) {
87+ success = GetOverlappedResult (m_handle, &ov, &bytes_read,
88+ /* bWait=*/ TRUE );
89+ err = GetLastError ();
90+ }
91+ if (success) {
92+ success =
93+ PeekNamedPipe (m_handle, NULL , 0 , NULL , &bytes_available, NULL );
94+ err = GetLastError ();
95+ }
96+ if (success) {
97+ if (bytes_available == 0 ) {
98+ // This can happen with a zero-byte write. Try again.
99+ continue ;
100+ }
101+ } else if (err == ERROR_NO_DATA) {
102+ // The pipe is nonblocking. Try again.
103+ Sleep (0 );
104+ continue ;
105+ } else if (err == ERROR_OPERATION_ABORTED) {
106+ // Read may have been cancelled, try again.
107+ continue ;
108+ }
109+
110+ SetEvent ((HANDLE)m_event);
111+
112+ // Wait until the current read is consumed before doing the next read.
113+ WaitForSingleObject (m_ready, INFINITE);
114+ } while (!m_stopped);
115+ }
116+
117+ private:
118+ HANDLE m_handle;
119+ HANDLE m_ready;
120+ std::thread m_monitor_thread;
121+ std::atomic<bool > m_stopped = false ;
122+ };
123+
124+ class SocketEvent : public MainLoopWindows ::IOEvent {
125+ public:
126+ explicit SocketEvent (SOCKET socket)
127+ : IOEvent((IOObject::WaitableHandle)WSACreateEvent()), m_socket(socket) {
128+ assert (event != WSA_INVALID_EVENT);
129+ }
130+
131+ ~SocketEvent () override { WSACloseEvent ((HANDLE)m_event); }
132+
133+ void WillPoll () {
134+ int result = WSAEventSelect (m_socket, (HANDLE)m_event,
135+ FD_READ | FD_ACCEPT | FD_CLOSE);
136+ assert (result == 0 );
137+ UNUSED_IF_ASSERT_DISABLED (result);
138+ }
139+
140+ void DidPoll () {
141+ int result = WSAEventSelect (m_socket, WSA_INVALID_EVENT, 0 );
142+ assert (result == 0 );
143+ UNUSED_IF_ASSERT_DISABLED (result);
144+ }
145+
146+ void Disarm () override { WSAResetEvent ((HANDLE)m_event); }
147+
148+ SOCKET m_socket;
149+ };
150+
151+ } // namespace
152+
34153MainLoopWindows::MainLoopWindows () {
35154 m_interrupt_event = WSACreateEvent ();
36155 assert (m_interrupt_event != WSA_INVALID_EVENT);
@@ -44,26 +163,20 @@ MainLoopWindows::~MainLoopWindows() {
44163}
45164
46165llvm::Expected<size_t > MainLoopWindows::Poll () {
47- std::vector<WSAEVENT > events;
166+ std::vector<HANDLE > events;
48167 events.reserve (m_read_fds.size () + 1 );
49- for (auto &[fd, info] : m_read_fds) {
50- int result = WSAEventSelect (fd, info.event , FD_READ | FD_ACCEPT | FD_CLOSE);
51- assert (result == 0 );
52- UNUSED_IF_ASSERT_DISABLED (result);
53-
54- events.push_back (info.event );
168+ for (auto &[_, fd_info] : m_read_fds) {
169+ fd_info.event ->WillPoll ();
170+ events.push_back ((HANDLE)fd_info.event ->GetHandle ());
55171 }
56172 events.push_back (m_interrupt_event);
57173
58174 DWORD result =
59175 WSAWaitForMultipleEvents (events.size (), events.data (), FALSE ,
60176 ToTimeout (GetNextWakeupTime ()), FALSE );
61177
62- for (auto &fd : m_read_fds) {
63- int result = WSAEventSelect (fd.first , WSA_INVALID_EVENT, 0 );
64- assert (result == 0 );
65- UNUSED_IF_ASSERT_DISABLED (result);
66- }
178+ for (auto &[_, fd_info] : m_read_fds)
179+ fd_info.event ->DidPoll ();
67180
68181 if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + events.size ())
69182 return result - WSA_WAIT_EVENT_0;
@@ -83,28 +196,25 @@ MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
83196 error = Status::FromErrorString (" IO object is not valid." );
84197 return nullptr ;
85198 }
86- if (object_sp->GetFdType () != IOObject::eFDTypeSocket) {
87- error = Status::FromErrorString (
88- " MainLoopWindows: non-socket types unsupported on Windows" );
89- return nullptr ;
90- }
91199
92- WSAEVENT event = WSACreateEvent ();
93- if (event == WSA_INVALID_EVENT) {
94- error =
95- Status::FromErrorStringWithFormat (" Cannot create monitoring event." );
200+ IOObject::WaitableHandle waitable_handle = object_sp->GetWaitableHandle ();
201+ assert (waitable_handle != IOObject::kInvalidHandleValue );
202+
203+ if (m_read_fds.find (waitable_handle) != m_read_fds.end ()) {
204+ error = Status::FromErrorStringWithFormat (
205+ " File descriptor %d already monitored." , waitable_handle);
96206 return nullptr ;
97207 }
98208
99- const bool inserted =
100- m_read_fds
101- . try_emplace (object_sp-> GetWaitableHandle (), FdInfo{event, callback})
102- . second ;
103- if (!inserted) {
104- WSACloseEvent (event) ;
105- error = Status::FromErrorStringWithFormat (
106- " File descriptor %d already monitored. " ,
107- object_sp-> GetWaitableHandle ( ));
209+ if (object_sp-> GetFdType () == IOObject::eFDTypeSocket)
210+ m_read_fds[waitable_handle] = {
211+ std::make_unique<SocketEvent>((SOCKET)waitable_handle), callback};
212+ else if ( GetFileType (waitable_handle) == FILE_TYPE_PIPE)
213+ m_read_fds[waitable_handle] = {
214+ std::make_unique<PipeEvent>((HANDLE)waitable_handle), callback} ;
215+ else {
216+ error = Status::FromErrorStringWithFormat ( " Unsupported file type %d " ,
217+ GetFileType (waitable_handle ));
108218 return nullptr ;
109219 }
110220
@@ -114,18 +224,9 @@ MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
114224void MainLoopWindows::UnregisterReadObject (IOObject::WaitableHandle handle) {
115225 auto it = m_read_fds.find (handle);
116226 assert (it != m_read_fds.end ());
117- BOOL result = WSACloseEvent (it->second .event );
118- assert (result == TRUE );
119- UNUSED_IF_ASSERT_DISABLED (result);
120227 m_read_fds.erase (it);
121228}
122229
123- void MainLoopWindows::ProcessReadObject (IOObject::WaitableHandle handle) {
124- auto it = m_read_fds.find (handle);
125- if (it != m_read_fds.end ())
126- it->second .callback (*this ); // Do the work
127- }
128-
129230Status MainLoopWindows::Run () {
130231 m_terminate_request = false ;
131232
@@ -138,8 +239,8 @@ Status MainLoopWindows::Run() {
138239
139240 if (*signaled_event < m_read_fds.size ()) {
140241 auto &KV = *std::next (m_read_fds.begin (), *signaled_event);
141- WSAResetEvent ( KV.second .event );
142- ProcessReadObject ( KV.first );
242+ KV.second .event -> Disarm ( );
243+ KV.second . callback (* this ); // Do the work.
143244 } else {
144245 assert (*signaled_event == m_read_fds.size ());
145246 WSAResetEvent (m_interrupt_event);
0 commit comments