mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
110 lines
2.9 KiB
C++
110 lines
2.9 KiB
C++
// Copyright (c) FIRST and other WPILib contributors.
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
// the WPILib BSD license file in the root directory of this project.
|
|
|
|
#include "ResolverThread.h"
|
|
|
|
#include "wpi/mutex.h"
|
|
|
|
using namespace wpi;
|
|
|
|
ResolverThread::ResolverThread(const private_init&) {}
|
|
|
|
ResolverThread::~ResolverThread() noexcept {
|
|
running = false;
|
|
if (thread.joinable()) {
|
|
thread.join();
|
|
}
|
|
}
|
|
|
|
void ResolverThread::AddServiceRef(DNSServiceRef serviceRef,
|
|
dnssd_sock_t socket) {
|
|
std::scoped_lock lock{serviceRefMutex};
|
|
serviceRefs.emplace_back(
|
|
std::pair<DNSServiceRef, dnssd_sock_t>{serviceRef, socket});
|
|
if (serviceRefs.size() == 1) {
|
|
running = false;
|
|
if (thread.joinable()) {
|
|
thread.join();
|
|
}
|
|
running = true;
|
|
thread = std::thread([=] { ThreadMain(); });
|
|
}
|
|
}
|
|
|
|
void ResolverThread::RemoveServiceRefInThread(DNSServiceRef serviceRef) {
|
|
std::scoped_lock lock{serviceRefMutex};
|
|
serviceRefs.erase(
|
|
std::find_if(serviceRefs.begin(), serviceRefs.end(),
|
|
[=](auto& a) { return a.first == serviceRef; }));
|
|
DNSServiceRefDeallocate(serviceRef);
|
|
}
|
|
|
|
WPI_EventHandle ResolverThread::RemoveServiceRefOutsideThread(
|
|
DNSServiceRef serviceRef) {
|
|
std::scoped_lock lock{serviceRefMutex};
|
|
WPI_EventHandle handle = CreateEvent(true);
|
|
serviceRefsToRemove.push_back({serviceRef, handle});
|
|
return handle;
|
|
}
|
|
|
|
bool ResolverThread::CleanupRefs() {
|
|
std::scoped_lock lock{serviceRefMutex};
|
|
for (auto&& r : serviceRefsToRemove) {
|
|
serviceRefs.erase(
|
|
std::find_if(serviceRefs.begin(), serviceRefs.end(),
|
|
[=](auto& a) { return a.first == r.first; }));
|
|
DNSServiceRefDeallocate(r.first);
|
|
wpi::SetEvent(r.second);
|
|
}
|
|
serviceRefsToRemove.clear();
|
|
return serviceRefs.empty();
|
|
}
|
|
|
|
void ResolverThread::ThreadMain() {
|
|
std::vector<pollfd> readSockets;
|
|
std::vector<DNSServiceRef> serviceRefs;
|
|
|
|
while (running) {
|
|
readSockets.clear();
|
|
serviceRefs.clear();
|
|
|
|
for (auto&& i : this->serviceRefs) {
|
|
readSockets.emplace_back(pollfd{i.second, POLLIN, 0});
|
|
serviceRefs.emplace_back(i.first);
|
|
}
|
|
|
|
int res = poll(readSockets.begin().base(), readSockets.size(), 100);
|
|
|
|
if (res > 0) {
|
|
for (size_t i = 0; i < readSockets.size(); i++) {
|
|
if (readSockets[i].revents == POLLIN) {
|
|
DNSServiceProcessResult(serviceRefs[i]);
|
|
}
|
|
}
|
|
} else if (res == 0) {
|
|
if (!running) {
|
|
CleanupRefs();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CleanupRefs()) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static wpi::mutex ThreadLoopLock;
|
|
static std::weak_ptr<ResolverThread> ThreadLoop;
|
|
|
|
std::shared_ptr<ResolverThread> ResolverThread::Get() {
|
|
std::scoped_lock lock{ThreadLoopLock};
|
|
auto locked = ThreadLoop.lock();
|
|
if (!locked) {
|
|
locked = std::make_unique<ResolverThread>(private_init{});
|
|
ThreadLoop = locked;
|
|
}
|
|
return locked;
|
|
}
|