[wpinet] uv: Stop creating handles when closing loop (#5102)

This prevents EventLoopRunner::Stop() from hanging in the case when
new handles are created after the async walk closes all the handles.
This commit is contained in:
Peter Johnson
2023-02-16 22:49:14 -08:00
committed by GitHub
parent 805c837a42
commit 8068369542
29 changed files with 300 additions and 82 deletions

View File

@@ -155,7 +155,9 @@ void NCImpl::SetServers(
[this, servers = std::move(serversCopy)](uv::Loop&) mutable {
m_servers = std::move(servers);
if (m_dsClientServer.first.empty()) {
m_parallelConnect->SetServers(m_servers);
if (m_parallelConnect) {
m_parallelConnect->SetServers(m_servers);
}
}
});
}
@@ -167,14 +169,20 @@ void NCImpl::StartDSClient(unsigned int port) {
}
m_dsClientServer.second = port == 0 ? NT_DEFAULT_PORT4 : port;
m_dsClient = wpi::DsClient::Create(m_loop, m_logger);
m_dsClient->setIp.connect([this](std::string_view ip) {
m_dsClientServer.first = ip;
m_parallelConnect->SetServers({{m_dsClientServer}});
});
m_dsClient->clearIp.connect([this] {
m_dsClientServer.first.clear();
m_parallelConnect->SetServers(m_servers);
});
if (m_dsClient) {
m_dsClient->setIp.connect([this](std::string_view ip) {
m_dsClientServer.first = ip;
if (m_parallelConnect) {
m_parallelConnect->SetServers({{m_dsClientServer}});
}
});
m_dsClient->clearIp.connect([this] {
m_dsClientServer.first.clear();
if (m_parallelConnect) {
m_parallelConnect->SetServers(m_servers);
}
});
}
});
}
@@ -191,15 +199,20 @@ void NCImpl::Disconnect(std::string_view reason) {
if (m_readLocalTimer) {
m_readLocalTimer->Stop();
}
m_sendValuesTimer->Stop();
if (m_sendValuesTimer) {
m_sendValuesTimer->Stop();
}
m_localStorage.ClearNetwork();
m_localQueue.ClearQueue();
m_connList.RemoveConnection(m_connHandle);
m_connHandle = 0;
// start trying to connect again
uv::Timer::SingleShot(m_loop, kReconnectRate,
[this] { m_parallelConnect->Disconnected(); });
uv::Timer::SingleShot(m_loop, kReconnectRate, [this] {
if (m_parallelConnect) {
m_parallelConnect->Disconnected();
}
});
}
NCImpl3::NCImpl3(int inst, std::string_view id,
@@ -212,25 +225,31 @@ NCImpl3::NCImpl3(int inst, std::string_view id,
[this](uv::Tcp& tcp) { TcpConnected(tcp); });
m_sendValuesTimer = uv::Timer::Create(loop);
m_sendValuesTimer->timeout.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendPeriodic(m_loop.Now().count(), false);
}
});
if (m_sendValuesTimer) {
m_sendValuesTimer->timeout.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendPeriodic(m_loop.Now().count(), false);
}
});
}
// set up flush async
m_flush = uv::Async<>::Create(m_loop);
m_flush->wakeup.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendPeriodic(m_loop.Now().count(), true);
}
});
if (m_flush) {
m_flush->wakeup.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendPeriodic(m_loop.Now().count(), true);
}
});
}
m_flushAtomic = m_flush.get();
m_flushLocal = uv::Async<>::Create(m_loop);
m_flushLocal->wakeup.connect([this] { HandleLocal(); });
if (m_flushLocal) {
m_flushLocal->wakeup.connect([this] { HandleLocal(); });
}
m_flushLocalAtomic = m_flushLocal.get();
});
}
@@ -261,8 +280,10 @@ void NCImpl3::TcpConnected(uv::Tcp& tcp) {
auto clientImpl = std::make_shared<net3::ClientImpl3>(
m_loop.Now().count(), m_inst, *wire, m_logger, [this](uint32_t repeatMs) {
DEBUG4("Setting periodic timer to {}", repeatMs);
m_sendValuesTimer->Start(uv::Timer::Time{repeatMs},
uv::Timer::Time{repeatMs});
if (m_sendValuesTimer) {
m_sendValuesTimer->Start(uv::Timer::Time{repeatMs},
uv::Timer::Time{repeatMs});
}
});
clientImpl->Start(
m_id, [this, wire,
@@ -276,7 +297,9 @@ void NCImpl3::TcpConnected(uv::Tcp& tcp) {
return;
}
m_parallelConnect->Succeeded(tcp);
if (m_parallelConnect) {
m_parallelConnect->Succeeded(tcp);
}
m_wire = std::move(wire);
m_clientImpl = std::move(clientImpl);
@@ -343,34 +366,42 @@ NCImpl4::NCImpl4(
[this](uv::Tcp& tcp) { TcpConnected(tcp); });
m_readLocalTimer = uv::Timer::Create(loop);
m_readLocalTimer->timeout.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendControl(m_loop.Now().count());
}
});
m_readLocalTimer->Start(uv::Timer::Time{100}, uv::Timer::Time{100});
if (m_readLocalTimer) {
m_readLocalTimer->timeout.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendControl(m_loop.Now().count());
}
});
m_readLocalTimer->Start(uv::Timer::Time{100}, uv::Timer::Time{100});
}
m_sendValuesTimer = uv::Timer::Create(loop);
m_sendValuesTimer->timeout.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendValues(m_loop.Now().count(), false);
}
});
if (m_sendValuesTimer) {
m_sendValuesTimer->timeout.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendValues(m_loop.Now().count(), false);
}
});
}
// set up flush async
m_flush = uv::Async<>::Create(m_loop);
m_flush->wakeup.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendValues(m_loop.Now().count(), true);
}
});
if (m_flush) {
m_flush->wakeup.connect([this] {
if (m_clientImpl) {
HandleLocal();
m_clientImpl->SendValues(m_loop.Now().count(), true);
}
});
}
m_flushAtomic = m_flush.get();
m_flushLocal = uv::Async<>::Create(m_loop);
m_flushLocal->wakeup.connect([this] { HandleLocal(); });
if (m_flushLocal) {
m_flushLocal->wakeup.connect([this] { HandleLocal(); });
}
m_flushLocalAtomic = m_flushLocal.get();
});
}
@@ -418,7 +449,9 @@ void NCImpl4::TcpConnected(uv::Tcp& tcp) {
}
void NCImpl4::WsConnected(wpi::WebSocket& ws, uv::Tcp& tcp) {
m_parallelConnect->Succeeded(tcp);
if (m_parallelConnect) {
m_parallelConnect->Succeeded(tcp);
}
ConnectionInfo connInfo;
uv::AddrToName(tcp.GetPeer(), &connInfo.remote_ip, &connInfo.remote_port);
@@ -432,8 +465,10 @@ void NCImpl4::WsConnected(wpi::WebSocket& ws, uv::Tcp& tcp) {
m_loop.Now().count(), m_inst, *m_wire, m_logger, m_timeSyncUpdated,
[this](uint32_t repeatMs) {
DEBUG4("Setting periodic timer to {}", repeatMs);
m_sendValuesTimer->Start(uv::Timer::Time{repeatMs},
uv::Timer::Time{repeatMs});
if (m_sendValuesTimer) {
m_sendValuesTimer->Start(uv::Timer::Time{repeatMs},
uv::Timer::Time{repeatMs});
}
});
m_clientImpl->SetLocal(&m_localStorage);
m_localStorage.StartNetwork(&m_localQueue);

View File

@@ -420,36 +420,46 @@ void NSImpl::Init() {
// set up timers
m_readLocalTimer = uv::Timer::Create(m_loop);
m_readLocalTimer->timeout.connect([this] {
HandleLocal();
m_serverImpl.SendControl(m_loop.Now().count());
});
m_readLocalTimer->Start(uv::Timer::Time{100}, uv::Timer::Time{100});
if (m_readLocalTimer) {
m_readLocalTimer->timeout.connect([this] {
HandleLocal();
m_serverImpl.SendControl(m_loop.Now().count());
});
m_readLocalTimer->Start(uv::Timer::Time{100}, uv::Timer::Time{100});
}
m_savePersistentTimer = uv::Timer::Create(m_loop);
m_savePersistentTimer->timeout.connect([this] {
if (m_serverImpl.PersistentChanged()) {
uv::QueueWork(
m_loop,
[this, fn = m_persistentFilename,
data = m_serverImpl.DumpPersistent()] { SavePersistent(fn, data); },
nullptr);
}
});
m_savePersistentTimer->Start(uv::Timer::Time{1000}, uv::Timer::Time{1000});
if (m_savePersistentTimer) {
m_savePersistentTimer->timeout.connect([this] {
if (m_serverImpl.PersistentChanged()) {
uv::QueueWork(
m_loop,
[this, fn = m_persistentFilename,
data = m_serverImpl.DumpPersistent()] {
SavePersistent(fn, data);
},
nullptr);
}
});
m_savePersistentTimer->Start(uv::Timer::Time{1000}, uv::Timer::Time{1000});
}
// set up flush async
m_flush = uv::Async<>::Create(m_loop);
m_flush->wakeup.connect([this] {
HandleLocal();
for (auto&& conn : m_connections) {
m_serverImpl.SendValues(conn.conn->GetClientId(), m_loop.Now().count());
}
});
if (m_flush) {
m_flush->wakeup.connect([this] {
HandleLocal();
for (auto&& conn : m_connections) {
m_serverImpl.SendValues(conn.conn->GetClientId(), m_loop.Now().count());
}
});
}
m_flushAtomic = m_flush.get();
m_flushLocal = uv::Async<>::Create(m_loop);
m_flushLocal->wakeup.connect([this] { HandleLocal(); });
if (m_flushLocal) {
m_flushLocal->wakeup.connect([this] { HandleLocal(); });
}
m_flushLocalAtomic = m_flushLocal.get();
INFO("Listening on NT3 port {}, NT4 port {}", m_port3, m_port4);