8
8
9
9
#include " lldb/Host/windows/MainLoopWindows.h"
10
10
#include " lldb/Host/Config.h"
11
+ #include " lldb/Host/Socket.h"
11
12
#include " lldb/Utility/Status.h"
12
13
#include " llvm/Config/llvm-config.h"
14
+ #include " llvm/Support/Casting.h"
15
+ #include " llvm/Support/WindowsError.h"
13
16
#include < algorithm>
14
17
#include < cassert>
15
18
#include < cerrno>
@@ -31,6 +34,122 @@ static DWORD ToTimeout(std::optional<MainLoopWindows::TimePoint> point) {
31
34
return ceil<milliseconds>(dur).count ();
32
35
}
33
36
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
+
34
153
MainLoopWindows::MainLoopWindows () {
35
154
m_interrupt_event = WSACreateEvent ();
36
155
assert (m_interrupt_event != WSA_INVALID_EVENT);
@@ -44,26 +163,20 @@ MainLoopWindows::~MainLoopWindows() {
44
163
}
45
164
46
165
llvm::Expected<size_t > MainLoopWindows::Poll () {
47
- std::vector<WSAEVENT > events;
166
+ std::vector<HANDLE > events;
48
167
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 ());
55
171
}
56
172
events.push_back (m_interrupt_event);
57
173
58
174
DWORD result =
59
175
WSAWaitForMultipleEvents (events.size (), events.data (), FALSE ,
60
176
ToTimeout (GetNextWakeupTime ()), FALSE );
61
177
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 ();
67
180
68
181
if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + events.size ())
69
182
return result - WSA_WAIT_EVENT_0;
@@ -83,28 +196,25 @@ MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
83
196
error = Status::FromErrorString (" IO object is not valid." );
84
197
return nullptr ;
85
198
}
86
- if (object_sp->GetFdType () != IOObject::eFDTypeSocket) {
87
- error = Status::FromErrorString (
88
- " MainLoopWindows: non-socket types unsupported on Windows" );
89
- return nullptr ;
90
- }
91
199
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);
96
206
return nullptr ;
97
207
}
98
208
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 ));
108
218
return nullptr ;
109
219
}
110
220
@@ -114,18 +224,9 @@ MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
114
224
void MainLoopWindows::UnregisterReadObject (IOObject::WaitableHandle handle) {
115
225
auto it = m_read_fds.find (handle);
116
226
assert (it != m_read_fds.end ());
117
- BOOL result = WSACloseEvent (it->second .event );
118
- assert (result == TRUE );
119
- UNUSED_IF_ASSERT_DISABLED (result);
120
227
m_read_fds.erase (it);
121
228
}
122
229
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
-
129
230
Status MainLoopWindows::Run () {
130
231
m_terminate_request = false ;
131
232
@@ -138,8 +239,8 @@ Status MainLoopWindows::Run() {
138
239
139
240
if (*signaled_event < m_read_fds.size ()) {
140
241
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.
143
244
} else {
144
245
assert (*signaled_event == m_read_fds.size ());
145
246
WSAResetEvent (m_interrupt_event);
0 commit comments