10#include "lldb/Host/Config.h"
14#include "llvm/Config/llvm-config.h"
15#include "llvm/Support/WindowsError.h"
31static DWORD
ToTimeout(std::optional<MainLoopWindows::TimePoint> point) {
32 using namespace std::chrono;
37 nanoseconds dur = (std::max)(*point - steady_clock::now(), nanoseconds(0));
38 return ceil<milliseconds>(dur).count();
45 explicit PipeEvent(
HANDLE handle)
46 : IOEvent(CreateEventW(nullptr, TRUE,
49 m_ready(CreateEventW(nullptr, TRUE,
51 m_stop(CreateEventW(nullptr, TRUE,
53 m_read_done(CreateEventW(nullptr, TRUE,
55 m_exited(CreateEventW(nullptr, TRUE,
57 assert(m_event && m_ready && m_stop && m_read_done && m_exited);
58 m_monitor_thread = std::thread(&PipeEvent::Monitor,
this);
61 ~PipeEvent()
override {
62 if (m_monitor_thread.joinable()) {
64 std::lock_guard<std::mutex> guard(m_mutex);
70 CancelIoEx(m_handle, &m_ov);
71 }
while (WaitForSingleObject(m_exited, 1) == WAIT_TIMEOUT);
72 m_monitor_thread.join();
77 CloseHandle(m_read_done);
78 CloseHandle(m_exited);
81 void WillPoll()
override {
82 std::lock_guard<std::mutex> guard(m_mutex);
84 HANDLE handles[2] = {m_event, m_ready};
85 if (WaitForMultipleObjects(2, handles, FALSE,
97 void Disarm()
override {
98 std::lock_guard<std::mutex> guard(m_mutex);
106 WaitForSingleObject(m_ready, INFINITE);
110 DWORD bytes_read = 0;
111 ZeroMemory(&m_ov,
sizeof(m_ov));
112 m_ov.hEvent = m_read_done;
116 BOOL success = ReadFile(m_handle, buf, 0,
118 DWORD bytes_available = 0;
119 DWORD err = GetLastError();
120 if (!success && err == ERROR_IO_PENDING) {
123 HANDLE handles[2] = {m_read_done, m_stop};
124 if (WaitForMultipleObjects(2, handles, FALSE, INFINITE) !=
126 CancelIoEx(m_handle, &m_ov);
127 GetOverlappedResult(m_handle, &m_ov, &bytes_read, TRUE);
130 success = GetOverlappedResult(m_handle, &m_ov, &bytes_read,
132 err = GetLastError();
135 success = PeekNamedPipe(m_handle,
nullptr, 0,
nullptr, &bytes_available,
137 err = GetLastError();
140 if (bytes_available == 0) {
144 }
else if (err == ERROR_NO_DATA) {
148 }
else if (err == ERROR_OPERATION_ABORTED) {
153 std::lock_guard<std::mutex> guard(m_mutex);
168 WaitForSingleObject(m_ready, INFINITE);
180 std::thread m_monitor_thread;
181 std::atomic<bool> m_stopped =
false;
187 explicit SocketEvent(SOCKET socket)
188 : IOEvent(WSACreateEvent()), m_socket(socket) {
189 assert(m_event != WSA_INVALID_EVENT);
192 ~SocketEvent()
override { WSACloseEvent(m_event); }
194 void WillPoll()
override {
196 WSAEventSelect(m_socket, m_event, FD_READ | FD_ACCEPT | FD_CLOSE);
201 void DidPoll()
override {
202 int result = WSAEventSelect(m_socket, WSA_INVALID_EVENT, 0);
207 void Disarm()
override { WSAResetEvent(m_event); }
222 assert(result == TRUE);
227 std::vector<HANDLE> events;
230 fd_info.event->WillPoll();
231 events.push_back(fd_info.event->GetHandle());
236 WSAWaitForMultipleEvents(events.size(), events.data(), FALSE,
240 fd_info.event->DidPoll();
242 if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + events.size())
243 return result - WSA_WAIT_EVENT_0;
246 if (result == WSA_WAIT_TIMEOUT)
247 return events.size() - 1;
249 return llvm::createStringError(llvm::inconvertibleErrorCode(),
250 "WSAWaitForMultipleEvents failed");
256 if (!object_sp || !object_sp->IsValid()) {
266 "File descriptor %p already monitored.", waitable_handle);
272 std::make_unique<SocketEvent>(
273 reinterpret_cast<SOCKET
>(waitable_handle)),
276 DWORD file_type = GetFileType(waitable_handle);
277 if (file_type != FILE_TYPE_CHAR && file_type != FILE_TYPE_PIPE) {
283 m_read_fds[waitable_handle] = {std::make_unique<PipeEvent>(waitable_handle),
302 llvm::Expected<size_t> signaled_event =
Poll();
307 auto &KV = *std::next(
m_read_fds.begin(), *signaled_event);
308 KV.second.event->Disarm();
309 KV.second.callback(*
this);
static llvm::raw_ostream & error(Stream &strm)
static DWORD ToTimeout(std::optional< MainLoopWindows::TimePoint > point)
static const WaitableHandle kInvalidHandleValue
lldb::file_t WaitableHandle
std::unique_ptr< ReadHandle > ReadHandleUP
std::optional< TimePoint > GetNextWakeupTime()
ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp)
std::function< void(MainLoopBase &)> Callback
llvm::Expected< size_t > Poll()
~MainLoopWindows() override
llvm::DenseMap< IOObject::WaitableHandle, FdInfo > m_read_fds
bool Interrupt() override
Interrupt the loop that is currently waiting for events.
ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error) override
void UnregisterReadObject(IOObject::WaitableHandle handle) override
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
#define UNUSED_IF_ASSERT_DISABLED(x)
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::IOObject > IOObjectSP