This patch switches the MainLoop class to use the WSAEventSelect mechanism to wait for multiple sockets to become readable. The motivation for doing that is that this allows us to wait for other kinds of events as well (as long as they can be converted to WSAEvents). This will allow us to avoid (abstract away) pipe-based multiplexing mechanisms in the generic code, since pipes cannot be combined with sockets on windows. Since the windows implementation will now look completely different than the posix (file descriptor-based) implementations, I have split the MainLoop class into two (MainLoopPosix and MainLoopWindows), with the common code going into MainLoopBase. Differential Revision: https://reviews.llvm.org/D131159
116 lines
3.4 KiB
C++
116 lines
3.4 KiB
C++
//===-- MainLoopWindows.cpp -----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Host/windows/MainLoopWindows.h"
|
|
#include "lldb/Host/Config.h"
|
|
#include "lldb/Utility/Status.h"
|
|
#include "llvm/Config/llvm-config.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cerrno>
|
|
#include <csignal>
|
|
#include <ctime>
|
|
#include <vector>
|
|
#include <winsock2.h>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
llvm::Expected<size_t> MainLoopWindows::Poll() {
|
|
std::vector<WSAEVENT> read_events;
|
|
read_events.reserve(m_read_fds.size());
|
|
for (auto &[fd, info] : m_read_fds) {
|
|
int result = WSAEventSelect(fd, info.event, FD_READ | FD_ACCEPT | FD_CLOSE);
|
|
assert(result == 0);
|
|
|
|
read_events.push_back(info.event);
|
|
}
|
|
|
|
DWORD result = WSAWaitForMultipleEvents(
|
|
read_events.size(), read_events.data(), FALSE, WSA_INFINITE, FALSE);
|
|
|
|
for (auto &fd : m_read_fds) {
|
|
int result = WSAEventSelect(fd.first, WSA_INVALID_EVENT, 0);
|
|
assert(result == 0);
|
|
}
|
|
|
|
if (result >= WSA_WAIT_EVENT_0 &&
|
|
result < WSA_WAIT_EVENT_0 + read_events.size())
|
|
return result - WSA_WAIT_EVENT_0;
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
"WSAWaitForMultipleEvents failed");
|
|
}
|
|
|
|
MainLoopWindows::ReadHandleUP
|
|
MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
|
|
const Callback &callback, Status &error) {
|
|
if (!object_sp || !object_sp->IsValid()) {
|
|
error.SetErrorString("IO object is not valid.");
|
|
return nullptr;
|
|
}
|
|
if (object_sp->GetFdType() != IOObject::eFDTypeSocket) {
|
|
error.SetErrorString(
|
|
"MainLoopWindows: non-socket types unsupported on Windows");
|
|
return nullptr;
|
|
}
|
|
|
|
WSAEVENT event = WSACreateEvent();
|
|
if (event == WSA_INVALID_EVENT) {
|
|
error.SetErrorStringWithFormat("Cannot create monitoring event.");
|
|
return nullptr;
|
|
}
|
|
|
|
const bool inserted =
|
|
m_read_fds
|
|
.try_emplace(object_sp->GetWaitableHandle(), FdInfo{event, callback})
|
|
.second;
|
|
if (!inserted) {
|
|
WSACloseEvent(event);
|
|
error.SetErrorStringWithFormat("File descriptor %d already monitored.",
|
|
object_sp->GetWaitableHandle());
|
|
return nullptr;
|
|
}
|
|
|
|
return CreateReadHandle(object_sp);
|
|
}
|
|
|
|
void MainLoopWindows::UnregisterReadObject(IOObject::WaitableHandle handle) {
|
|
auto it = m_read_fds.find(handle);
|
|
assert(it != m_read_fds.end());
|
|
BOOL result = WSACloseEvent(it->second.event);
|
|
assert(result == TRUE);
|
|
m_read_fds.erase(it);
|
|
}
|
|
|
|
void MainLoopWindows::ProcessReadObject(IOObject::WaitableHandle handle) {
|
|
auto it = m_read_fds.find(handle);
|
|
if (it != m_read_fds.end())
|
|
it->second.callback(*this); // Do the work
|
|
}
|
|
|
|
Status MainLoopWindows::Run() {
|
|
m_terminate_request = false;
|
|
|
|
Status error;
|
|
|
|
// run until termination or until we run out of things to listen to
|
|
while (!m_terminate_request && !m_read_fds.empty()) {
|
|
|
|
llvm::Expected<size_t> signaled_event = Poll();
|
|
if (!signaled_event)
|
|
return Status(signaled_event.takeError());
|
|
|
|
auto &KV = *std::next(m_read_fds.begin(), *signaled_event);
|
|
|
|
ProcessReadObject(KV.first);
|
|
ProcessPendingCallbacks();
|
|
}
|
|
return Status();
|
|
}
|