xref: /openbsd-src/gnu/llvm/lldb/source/Host/windows/MainLoopWindows.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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 
21 using namespace lldb;
22 using namespace lldb_private;
23 
MainLoopWindows()24 MainLoopWindows::MainLoopWindows() {
25   m_trigger_event = WSACreateEvent();
26   assert(m_trigger_event != WSA_INVALID_EVENT);
27 }
28 
~MainLoopWindows()29 MainLoopWindows::~MainLoopWindows() {
30   assert(m_read_fds.empty());
31   BOOL result = WSACloseEvent(m_trigger_event);
32   assert(result == TRUE);
33   (void)result;
34 }
35 
Poll()36 llvm::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     (void)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     (void)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(llvm::inconvertibleErrorCode(),
61                                  "WSAWaitForMultipleEvents failed");
62 }
63 
64 MainLoopWindows::ReadHandleUP
RegisterReadObject(const IOObjectSP & object_sp,const Callback & callback,Status & error)65 MainLoopWindows::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(object_sp->GetWaitableHandle(), 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 
UnregisterReadObject(IOObject::WaitableHandle handle)97 void MainLoopWindows::UnregisterReadObject(IOObject::WaitableHandle handle) {
98   auto it = m_read_fds.find(handle);
99   assert(it != m_read_fds.end());
100   BOOL result = WSACloseEvent(it->second.event);
101   assert(result == TRUE);
102   (void)result;
103   m_read_fds.erase(it);
104 }
105 
ProcessReadObject(IOObject::WaitableHandle handle)106 void MainLoopWindows::ProcessReadObject(IOObject::WaitableHandle handle) {
107   auto it = m_read_fds.find(handle);
108   if (it != m_read_fds.end())
109     it->second.callback(*this); // Do the work
110 }
111 
Run()112 Status 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(m_read_fds.begin(), *signaled_event);
126       ProcessReadObject(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 
TriggerPendingCallbacks()136 void MainLoopWindows::TriggerPendingCallbacks() {
137   WSASetEvent(m_trigger_event);
138 }
139