LLDB mainline
MainLoopWindows.cpp
Go to the documentation of this file.
1//===-- MainLoopWindows.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Host/Config.h"
11#include "lldb/Utility/Status.h"
12#include "llvm/Config/llvm-config.h"
13#include <algorithm>
14#include <cassert>
15#include <cerrno>
16#include <csignal>
17#include <ctime>
18#include <vector>
19#include <winsock2.h>
20
21using namespace lldb;
22using namespace lldb_private;
23
24static DWORD ToTimeout(std::optional<MainLoopWindows::TimePoint> point) {
25 using namespace std::chrono;
26
27 if (!point)
28 return WSA_INFINITE;
29
30 nanoseconds dur = (std::max)(*point - steady_clock::now(), nanoseconds(0));
31 return ceil<milliseconds>(dur).count();
32}
33
35 m_interrupt_event = WSACreateEvent();
36 assert(m_interrupt_event != WSA_INVALID_EVENT);
37}
38
40 assert(m_read_fds.empty());
41 BOOL result = WSACloseEvent(m_interrupt_event);
42 assert(result == TRUE);
44}
45
46llvm::Expected<size_t> MainLoopWindows::Poll() {
47 std::vector<WSAEVENT> events;
48 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);
53
54 events.push_back(info.event);
55 }
56 events.push_back(m_interrupt_event);
57
58 DWORD result =
59 WSAWaitForMultipleEvents(events.size(), events.data(), FALSE,
61
62 for (auto &fd : m_read_fds) {
63 int result = WSAEventSelect(fd.first, WSA_INVALID_EVENT, 0);
64 assert(result == 0);
66 }
67
68 if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + events.size())
69 return result - WSA_WAIT_EVENT_0;
70
71 // A timeout is treated as a (premature) signalization of the interrupt event.
72 if (result == WSA_WAIT_TIMEOUT)
73 return events.size() - 1;
74
75 return llvm::createStringError(llvm::inconvertibleErrorCode(),
76 "WSAWaitForMultipleEvents failed");
77}
78
81 const Callback &callback, Status &error) {
82 if (!object_sp || !object_sp->IsValid()) {
83 error = Status::FromErrorString("IO object is not valid.");
84 return nullptr;
85 }
86 if (object_sp->GetFdType() != IOObject::eFDTypeSocket) {
88 "MainLoopWindows: non-socket types unsupported on Windows");
89 return nullptr;
90 }
91
92 WSAEVENT event = WSACreateEvent();
93 if (event == WSA_INVALID_EVENT) {
94 error =
95 Status::FromErrorStringWithFormat("Cannot create monitoring event.");
96 return nullptr;
97 }
98
99 const bool inserted =
101 .try_emplace(object_sp->GetWaitableHandle(), FdInfo{event, callback})
102 .second;
103 if (!inserted) {
104 WSACloseEvent(event);
106 "File descriptor %d already monitored.",
107 object_sp->GetWaitableHandle());
108 return nullptr;
109 }
110
111 return CreateReadHandle(object_sp);
112}
113
115 auto it = m_read_fds.find(handle);
116 assert(it != m_read_fds.end());
117 BOOL result = WSACloseEvent(it->second.event);
118 assert(result == TRUE);
120 m_read_fds.erase(it);
121}
122
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
130 m_terminate_request = false;
131
133
134 while (!m_terminate_request) {
135 llvm::Expected<size_t> signaled_event = Poll();
136 if (!signaled_event)
137 return Status::FromError(signaled_event.takeError());
138
139 if (*signaled_event < m_read_fds.size()) {
140 auto &KV = *std::next(m_read_fds.begin(), *signaled_event);
141 WSAResetEvent(KV.second.event);
142 ProcessReadObject(KV.first);
143 } else {
144 assert(*signaled_event == m_read_fds.size());
145 WSAResetEvent(m_interrupt_event);
146 }
148 }
149 return Status();
150}
151
static llvm::raw_ostream & error(Stream &strm)
static DWORD ToTimeout(std::optional< MainLoopWindows::TimePoint > point)
std::unique_ptr< ReadHandle > ReadHandleUP
Definition: MainLoopBase.h:49
std::optional< TimePoint > GetNextWakeupTime()
ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp)
Definition: MainLoopBase.h:82
std::function< void(MainLoopBase &)> Callback
Definition: MainLoopBase.h:51
llvm::Expected< size_t > Poll()
llvm::DenseMap< IOObject::WaitableHandle, FdInfo > m_read_fds
ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error) override
void UnregisterReadObject(IOObject::WaitableHandle handle) override
void ProcessReadObject(IOObject::WaitableHandle handle)
An error handling class.
Definition: Status.h:115
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition: Status.cpp:106
static Status FromErrorString(const char *str)
Definition: Status.h:138
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition: Status.cpp:137
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:140
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::IOObject > IOObjectSP
Definition: lldb-forward.h:362