ControllerInterface: fix DSU thread safety and use PlatformPopulateDevices()
This commit is contained in:
parent
8b53af9cbc
commit
08f8c27927
|
@ -7,7 +7,6 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include <SFML/Network/SocketSelector.hpp>
|
#include <SFML/Network/SocketSelector.hpp>
|
||||||
|
@ -19,6 +18,7 @@
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
#include "Common/Random.h"
|
#include "Common/Random.h"
|
||||||
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
|
@ -192,12 +192,12 @@ struct Server
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
std::string m_address;
|
std::string m_address;
|
||||||
u16 m_port;
|
u16 m_port;
|
||||||
std::mutex m_port_info_mutex;
|
|
||||||
std::array<Proto::MessageType::PortInfo, Proto::PORT_COUNT> m_port_info;
|
std::array<Proto::MessageType::PortInfo, Proto::PORT_COUNT> m_port_info;
|
||||||
sf::UdpSocket m_socket;
|
sf::UdpSocket m_socket;
|
||||||
SteadyClock::time_point m_disconnect_time = SteadyClock::now();
|
SteadyClock::time_point m_disconnect_time = SteadyClock::now();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool s_has_init;
|
||||||
static bool s_servers_enabled;
|
static bool s_servers_enabled;
|
||||||
static std::vector<Server> s_servers;
|
static std::vector<Server> s_servers;
|
||||||
static u32 s_client_uid;
|
static u32 s_client_uid;
|
||||||
|
@ -217,6 +217,8 @@ static void HotplugThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("DualShockUDPClient Hotplug Thread");
|
Common::SetCurrentThreadName("DualShockUDPClient Hotplug Thread");
|
||||||
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread started");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread started");
|
||||||
|
Common::ScopeGuard thread_stop_guard{
|
||||||
|
[] { INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread stopped"); }};
|
||||||
|
|
||||||
std::vector<bool> timed_out_servers(s_servers.size(), false);
|
std::vector<bool> timed_out_servers(s_servers.size(), false);
|
||||||
|
|
||||||
|
@ -331,7 +333,6 @@ static void HotplugThreadFunc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread stopped");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StartHotplugThread()
|
static void StartHotplugThread()
|
||||||
|
@ -355,13 +356,15 @@ static void StopHotplugThread()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_hotplug_thread.join();
|
||||||
|
|
||||||
for (auto& server : s_servers)
|
for (auto& server : s_servers)
|
||||||
{
|
{
|
||||||
server.m_socket.unbind(); // interrupt blocking socket
|
server.m_socket.unbind(); // interrupt blocking socket
|
||||||
}
|
}
|
||||||
s_hotplug_thread.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also just start
|
||||||
static void Restart()
|
static void Restart()
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient Restart");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient Restart");
|
||||||
|
@ -377,7 +380,8 @@ static void Restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PopulateDevices(); // Only removes devices
|
// Only removes devices as servers have been cleaned
|
||||||
|
g_controller_interface.PlatformPopulateDevices([] { PopulateDevices(); });
|
||||||
|
|
||||||
s_client_uid = Common::Random::GenerateValue<u32>();
|
s_client_uid = Common::Random::GenerateValue<u32>();
|
||||||
s_next_listports_time = SteadyClock::now();
|
s_next_listports_time = SteadyClock::now();
|
||||||
|
@ -388,6 +392,9 @@ static void Restart()
|
||||||
|
|
||||||
static void ConfigChanged()
|
static void ConfigChanged()
|
||||||
{
|
{
|
||||||
|
if (!s_has_init)
|
||||||
|
return;
|
||||||
|
|
||||||
const bool servers_enabled = Config::Get(Settings::SERVERS_ENABLED);
|
const bool servers_enabled = Config::Get(Settings::SERVERS_ENABLED);
|
||||||
const std::string servers_setting = Config::Get(Settings::SERVERS);
|
const std::string servers_setting = Config::Get(Settings::SERVERS);
|
||||||
|
|
||||||
|
@ -400,6 +407,9 @@ static void ConfigChanged()
|
||||||
|
|
||||||
if (servers_enabled != s_servers_enabled || servers_setting != new_servers_setting)
|
if (servers_enabled != s_servers_enabled || servers_setting != new_servers_setting)
|
||||||
{
|
{
|
||||||
|
// Stop the thread before writing to s_servers
|
||||||
|
StopHotplugThread();
|
||||||
|
|
||||||
s_servers_enabled = servers_enabled;
|
s_servers_enabled = servers_enabled;
|
||||||
s_servers.clear();
|
s_servers.clear();
|
||||||
|
|
||||||
|
@ -427,6 +437,9 @@ static void ConfigChanged()
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
|
// Does not support multiple init calls
|
||||||
|
s_has_init = true;
|
||||||
|
|
||||||
// The following is added for backwards compatibility
|
// The following is added for backwards compatibility
|
||||||
const auto server_address_setting = Config::Get(Settings::SERVER_ADDRESS);
|
const auto server_address_setting = Config::Get(Settings::SERVER_ADDRESS);
|
||||||
const auto server_port_setting = Config::Get(Settings::SERVER_PORT);
|
const auto server_port_setting = Config::Get(Settings::SERVER_PORT);
|
||||||
|
@ -447,6 +460,10 @@ void Init()
|
||||||
ConfigChanged(); // Call it immediately to load settings
|
ConfigChanged(); // Call it immediately to load settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This can be called by the host thread as well as the hotplug thread, concurrently.
|
||||||
|
// So use PlatformPopulateDevices().
|
||||||
|
// s_servers is already safe because it can only be modified when the DSU thread is not running,
|
||||||
|
// from the main thread
|
||||||
void PopulateDevices()
|
void PopulateDevices()
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient PopulateDevices");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient PopulateDevices");
|
||||||
|
@ -457,9 +474,11 @@ void PopulateDevices()
|
||||||
g_controller_interface.RemoveDevice(
|
g_controller_interface.RemoveDevice(
|
||||||
[](const auto* dev) { return dev->GetSource() == DUALSHOCKUDP_SOURCE_NAME; });
|
[](const auto* dev) { return dev->GetSource() == DUALSHOCKUDP_SOURCE_NAME; });
|
||||||
|
|
||||||
for (auto& server : s_servers)
|
// Users might have created more than one server on the same IP/Port.
|
||||||
|
// Devices might end up being duplicated (if the server responds two all requests)
|
||||||
|
// but they won't conflict.
|
||||||
|
for (const auto& server : s_servers)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{server.m_port_info_mutex};
|
|
||||||
for (size_t port_index = 0; port_index < server.m_port_info.size(); port_index++)
|
for (size_t port_index = 0; port_index < server.m_port_info.size(); port_index++)
|
||||||
{
|
{
|
||||||
const Proto::MessageType::PortInfo& port_info = server.m_port_info[port_index];
|
const Proto::MessageType::PortInfo& port_info = server.m_port_info[port_index];
|
||||||
|
@ -475,6 +494,10 @@ void PopulateDevices()
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
StopHotplugThread();
|
StopHotplugThread();
|
||||||
|
|
||||||
|
s_has_init = false;
|
||||||
|
s_servers_enabled = false;
|
||||||
|
s_servers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(std::string name, int index, std::string server_address, u16 server_port)
|
Device::Device(std::string name, int index, std::string server_address, u16 server_port)
|
||||||
|
|
Loading…
Reference in New Issue