ControllerInterface: Shutdown order and race condition fix.

This commit is contained in:
Jordan Woyak 2019-01-02 08:19:42 -06:00
parent cddb83fd06
commit 25d43ffd98
2 changed files with 18 additions and 27 deletions

View File

@ -36,17 +36,16 @@
ControllerInterface g_controller_interface; ControllerInterface g_controller_interface;
//
// Init
//
// Detect devices and inputs outputs / will make refresh function later
//
void ControllerInterface::Initialize(const WindowSystemInfo& wsi) void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
{ {
if (m_is_init) if (m_is_init)
return; return;
m_wsi = wsi; m_wsi = wsi;
// Allow backends to add devices as soon as they are initialized.
m_is_init = true;
m_is_populating_devices = true; m_is_populating_devices = true;
#ifdef CIFACE_USE_DINPUT #ifdef CIFACE_USE_DINPUT
@ -76,7 +75,6 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
// nothing needed // nothing needed
#endif #endif
m_is_init = true;
RefreshDevices(); RefreshDevices();
} }
@ -136,16 +134,15 @@ void ControllerInterface::RefreshDevices()
InvokeDevicesChangedCallbacks(); InvokeDevicesChangedCallbacks();
} }
// // Remove all devices and call library cleanup functions
// DeInit
//
// Remove all devices/ call library cleanup functions
//
void ControllerInterface::Shutdown() void ControllerInterface::Shutdown()
{ {
if (!m_is_init) if (!m_is_init)
return; return;
// Prevent additional devices from being added during shutdown.
m_is_init = false;
{ {
std::lock_guard<std::mutex> lk(m_devices_mutex); std::lock_guard<std::mutex> lk(m_devices_mutex);
@ -159,6 +156,10 @@ void ControllerInterface::Shutdown()
m_devices.clear(); m_devices.clear();
} }
// This will update control references so shared_ptr<Device>s are freed up
// BEFORE we shutdown the backends.
InvokeDevicesChangedCallbacks();
#ifdef CIFACE_USE_XINPUT #ifdef CIFACE_USE_XINPUT
ciface::XInput::DeInit(); ciface::XInput::DeInit();
#endif #endif
@ -181,12 +182,14 @@ void ControllerInterface::Shutdown()
#ifdef CIFACE_USE_EVDEV #ifdef CIFACE_USE_EVDEV
ciface::evdev::Shutdown(); ciface::evdev::Shutdown();
#endif #endif
m_is_init = false;
} }
void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device) void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device)
{ {
// If we are shutdown (or in process of shutting down) ignore this request:
if (!m_is_init)
return;
{ {
std::lock_guard<std::mutex> lk(m_devices_mutex); std::lock_guard<std::mutex> lk(m_devices_mutex);
// Try to find an ID for this device // Try to find an ID for this device
@ -232,11 +235,7 @@ void ControllerInterface::RemoveDevice(std::function<bool(const ciface::Core::De
InvokeDevicesChangedCallbacks(); InvokeDevicesChangedCallbacks();
} }
// // Update input for all devices if lock can be acquired without waiting.
// UpdateInput
//
// Update input for all devices
//
void ControllerInterface::UpdateInput() void ControllerInterface::UpdateInput()
{ {
// Don't block the UI or CPU thread (to avoid a short but noticeable frame drop) // Don't block the UI or CPU thread (to avoid a short but noticeable frame drop)
@ -248,23 +247,15 @@ void ControllerInterface::UpdateInput()
} }
} }
//
// RegisterDevicesChangedCallback
//
// Register a callback to be called when a device is added or removed (as from the input backends' // Register a callback to be called when a device is added or removed (as from the input backends'
// hotplug thread), or when devices are refreshed // hotplug thread), or when devices are refreshed
//
void ControllerInterface::RegisterDevicesChangedCallback(std::function<void()> callback) void ControllerInterface::RegisterDevicesChangedCallback(std::function<void()> callback)
{ {
std::lock_guard<std::mutex> lk(m_callbacks_mutex); std::lock_guard<std::mutex> lk(m_callbacks_mutex);
m_devices_changed_callbacks.emplace_back(std::move(callback)); m_devices_changed_callbacks.emplace_back(std::move(callback));
} }
//
// InvokeDevicesChangedCallbacks
//
// Invoke all callbacks that were registered // Invoke all callbacks that were registered
//
void ControllerInterface::InvokeDevicesChangedCallbacks() const void ControllerInterface::InvokeDevicesChangedCallbacks() const
{ {
std::lock_guard<std::mutex> lk(m_callbacks_mutex); std::lock_guard<std::mutex> lk(m_callbacks_mutex);

View File

@ -56,7 +56,7 @@ public:
private: private:
std::vector<std::function<void()>> m_devices_changed_callbacks; std::vector<std::function<void()>> m_devices_changed_callbacks;
mutable std::mutex m_callbacks_mutex; mutable std::mutex m_callbacks_mutex;
bool m_is_init; std::atomic<bool> m_is_init;
std::atomic<bool> m_is_populating_devices{false}; std::atomic<bool> m_is_populating_devices{false};
WindowSystemInfo m_wsi; WindowSystemInfo m_wsi;
}; };