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 24 MainLoopWindows::MainLoopWindows() { 25 m_trigger_event = WSACreateEvent(); 26 assert(m_trigger_event != WSA_INVALID_EVENT); 27 } 28 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 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 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 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 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 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 136 void MainLoopWindows::TriggerPendingCallbacks() { 137 WSASetEvent(m_trigger_event); 138 } 139