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