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
9#include "lldb/Host/windows/MainLoopWindows.h"
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
24MainLoopWindows::MainLoopWindows() {
25 m_trigger_event = WSACreateEvent();
26 assert(m_trigger_event != WSA_INVALID_EVENT);
27}
28
29MainLoopWindows::~MainLoopWindows() {
30 assert(m_read_fds.empty());
31 BOOL result = WSACloseEvent(m_trigger_event);
32 assert(result == TRUE);
33 UNUSED_IF_ASSERT_DISABLED(result);
34}
35
36llvm::Expected<size_t> MainLoopWindows::Poll() {
37 std::vector<WSAEVENT> events;
38 events.reserve(m_read_fds.size() + 1);
39 for (auto &[fd, info] : m_read_fds) {
40 int result = WSAEventSelect(fd, info.event, FD_READ | FD_ACCEPT | FD_CLOSE);
41 assert(result == 0);
42 UNUSED_IF_ASSERT_DISABLED(result);
43
44 events.push_back(info.event);
45 }
46 events.push_back(m_trigger_event);
47
48 DWORD result = WSAWaitForMultipleEvents(events.size(), events.data(), FALSE,
49 WSA_INFINITE, FALSE);
50
51 for (auto &fd : m_read_fds) {
52 int result = WSAEventSelect(fd.first, WSA_INVALID_EVENT, 0);
53 assert(result == 0);
54 UNUSED_IF_ASSERT_DISABLED(result);
55 }
56
57 if (result >= WSA_WAIT_EVENT_0 && result <= WSA_WAIT_EVENT_0 + events.size())
58 return result - WSA_WAIT_EVENT_0;
59
60 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
61 Msg: "WSAWaitForMultipleEvents failed");
62}
63
64MainLoopWindows::ReadHandleUP
65MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
66 const Callback &callback, Status &error) {
67 if (!object_sp || !object_sp->IsValid()) {
68 error.SetErrorString("IO object is not valid.");
69 return nullptr;
70 }
71 if (object_sp->GetFdType() != IOObject::eFDTypeSocket) {
72 error.SetErrorString(
73 "MainLoopWindows: non-socket types unsupported on Windows");
74 return nullptr;
75 }
76
77 WSAEVENT event = WSACreateEvent();
78 if (event == WSA_INVALID_EVENT) {
79 error.SetErrorStringWithFormat("Cannot create monitoring event.");
80 return nullptr;
81 }
82
83 const bool inserted =
84 m_read_fds
85 .try_emplace(Key: object_sp->GetWaitableHandle(), Args: FdInfo{event, callback})
86 .second;
87 if (!inserted) {
88 WSACloseEvent(event);
89 error.SetErrorStringWithFormat("File descriptor %d already monitored.",
90 object_sp->GetWaitableHandle());
91 return nullptr;
92 }
93
94 return CreateReadHandle(object_sp);
95}
96
97void MainLoopWindows::UnregisterReadObject(IOObject::WaitableHandle handle) {
98 auto it = m_read_fds.find(Val: handle);
99 assert(it != m_read_fds.end());
100 BOOL result = WSACloseEvent(it->second.event);
101 assert(result == TRUE);
102 UNUSED_IF_ASSERT_DISABLED(result);
103 m_read_fds.erase(I: it);
104}
105
106void MainLoopWindows::ProcessReadObject(IOObject::WaitableHandle handle) {
107 auto it = m_read_fds.find(Val: handle);
108 if (it != m_read_fds.end())
109 it->second.callback(*this); // Do the work
110}
111
112Status MainLoopWindows::Run() {
113 m_terminate_request = false;
114
115 Status error;
116
117 // run until termination or until we run out of things to listen to
118 while (!m_terminate_request && !m_read_fds.empty()) {
119
120 llvm::Expected<size_t> signaled_event = Poll();
121 if (!signaled_event)
122 return Status(signaled_event.takeError());
123
124 if (*signaled_event < m_read_fds.size()) {
125 auto &KV = *std::next(x: m_read_fds.begin(), n: *signaled_event);
126 ProcessReadObject(handle: KV.first);
127 } else {
128 assert(*signaled_event == m_read_fds.size());
129 WSAResetEvent(m_trigger_event);
130 }
131 ProcessPendingCallbacks();
132 }
133 return Status();
134}
135
136void MainLoopWindows::TriggerPendingCallbacks() {
137 WSASetEvent(m_trigger_event);
138}
139

source code of lldb/source/Host/windows/MainLoopWindows.cpp