Modernize management of Udev pointers

This commit is contained in:
Chris Thrasher 2024-07-04 15:19:36 -06:00
parent f911d01e01
commit ee036b064c

View File

@ -32,6 +32,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <libudev.h> #include <libudev.h>
#include <linux/joystick.h> #include <linux/joystick.h>
#include <memory>
#include <ostream> #include <ostream>
#include <poll.h> #include <poll.h>
#include <string> #include <string>
@ -43,8 +44,34 @@
namespace namespace
{ {
udev* udevContext = nullptr; struct UdevDeleter
udev_monitor* udevMonitor = nullptr; {
void operator()(udev_device* device) const
{
udev_device_unref(device);
}
void operator()(udev_monitor* monitor) const
{
udev_monitor_unref(monitor);
}
void operator()(udev_enumerate* enumerate) const
{
udev_enumerate_unref(enumerate);
}
void operator()(udev* context) const
{
udev_unref(context);
}
};
template <typename T>
using UdevPtr = std::unique_ptr<T, UdevDeleter>;
UdevPtr<udev> udevContext;
UdevPtr<udev_monitor> udevMonitor;
struct JoystickRecord struct JoystickRecord
{ {
@ -181,7 +208,7 @@ void updatePluggedList(udev_device* udevDevice = nullptr)
for (JoystickRecord& record : joystickList) for (JoystickRecord& record : joystickList)
record.plugged = false; record.plugged = false;
udev_enumerate* udevEnumerator = udev_enumerate_new(udevContext); const auto udevEnumerator = UdevPtr<udev_enumerate>(udev_enumerate_new(udevContext.get()));
if (!udevEnumerator) if (!udevEnumerator)
{ {
@ -189,36 +216,30 @@ void updatePluggedList(udev_device* udevDevice = nullptr)
return; return;
} }
int result = 0; if (udev_enumerate_add_match_subsystem(udevEnumerator.get(), "input") < 0)
result = udev_enumerate_add_match_subsystem(udevEnumerator, "input");
if (result < 0)
{ {
sf::err() << "Error while adding udev enumerator match" << std::endl; sf::err() << "Error while adding udev enumerator match" << std::endl;
return; return;
} }
result = udev_enumerate_scan_devices(udevEnumerator); if (udev_enumerate_scan_devices(udevEnumerator.get()) < 0)
if (result < 0)
{ {
sf::err() << "Error while enumerating udev devices" << std::endl; sf::err() << "Error while enumerating udev devices" << std::endl;
return; return;
} }
udev_list_entry* devices = udev_enumerate_get_list_entry(udevEnumerator); udev_list_entry* devices = udev_enumerate_get_list_entry(udevEnumerator.get());
udev_list_entry* device = nullptr; udev_list_entry* device = nullptr;
udev_list_entry_foreach(device, devices) udev_list_entry_foreach(device, devices)
{ {
const char* syspath = udev_list_entry_get_name(device); const char* syspath = udev_list_entry_get_name(device);
udev_device* newUdevDevice = udev_device_new_from_syspath(udevContext, syspath); const auto newUdevDevice = UdevPtr<udev_device>(udev_device_new_from_syspath(udevContext.get(), syspath));
if (newUdevDevice && isJoystick(newUdevDevice)) if (newUdevDevice && isJoystick(newUdevDevice.get()))
{ {
// Since isJoystick returned true, this has to succeed // Since isJoystick returned true, this has to succeed
const char* devnode = udev_device_get_devnode(newUdevDevice); const char* devnode = udev_device_get_devnode(newUdevDevice.get());
JoystickList::iterator recordIt; JoystickList::iterator recordIt;
@ -243,17 +264,13 @@ void updatePluggedList(udev_device* udevDevice = nullptr)
joystickList.push_back(newRecord); joystickList.push_back(newRecord);
} }
} }
udev_device_unref(newUdevDevice);
} }
udev_enumerate_unref(udevEnumerator);
} }
bool hasMonitorEvent() bool hasMonitorEvent()
{ {
// This will not fail since we make sure udevMonitor is valid // This will not fail since we make sure udevMonitor is valid
const int monitorFd = udev_monitor_get_fd(udevMonitor); const int monitorFd = udev_monitor_get_fd(udevMonitor.get());
pollfd fds{monitorFd, POLLIN, 0}; pollfd fds{monitorFd, POLLIN, 0};
@ -316,7 +333,8 @@ unsigned int getJoystickVendorId(unsigned int index)
return 0; return 0;
} }
udev_device* udevDevice = udev_device_new_from_syspath(udevContext, joystickList[index].systemPath.c_str()); const auto udevDevice = UdevPtr<udev_device>(
udev_device_new_from_syspath(udevContext.get(), joystickList[index].systemPath.c_str()));
if (!udevDevice) if (!udevDevice)
{ {
@ -324,23 +342,12 @@ unsigned int getJoystickVendorId(unsigned int index)
return 0; return 0;
} }
unsigned int id = 0;
// First try using udev // First try using udev
id = getUdevAttributeUint(udevDevice, "ID_VENDOR_ID"); if (const unsigned int id = getUdevAttributeUint(udevDevice.get(), "ID_VENDOR_ID"))
if (id)
{
udev_device_unref(udevDevice);
return id; return id;
}
// Fall back to using USB attribute // Fall back to using USB attribute
id = getUsbAttributeUint(udevDevice, "idVendor"); if (const unsigned int id = getUsbAttributeUint(udevDevice.get(), "idVendor"))
udev_device_unref(udevDevice);
if (id)
return id; return id;
sf::err() << "Failed to get vendor ID of joystick " << joystickList[index].deviceNode << std::endl; sf::err() << "Failed to get vendor ID of joystick " << joystickList[index].deviceNode << std::endl;
@ -357,7 +364,8 @@ unsigned int getJoystickProductId(unsigned int index)
return 0; return 0;
} }
udev_device* udevDevice = udev_device_new_from_syspath(udevContext, joystickList[index].systemPath.c_str()); const auto udevDevice = UdevPtr<udev_device>(
udev_device_new_from_syspath(udevContext.get(), joystickList[index].systemPath.c_str()));
if (!udevDevice) if (!udevDevice)
{ {
@ -365,23 +373,12 @@ unsigned int getJoystickProductId(unsigned int index)
return 0; return 0;
} }
unsigned int id = 0;
// First try using udev // First try using udev
id = getUdevAttributeUint(udevDevice, "ID_MODEL_ID"); if (const unsigned int id = getUdevAttributeUint(udevDevice.get(), "ID_MODEL_ID"))
if (id)
{
udev_device_unref(udevDevice);
return id; return id;
}
// Fall back to using USB attribute // Fall back to using USB attribute
id = getUsbAttributeUint(udevDevice, "idProduct"); if (const unsigned int id = getUsbAttributeUint(udevDevice.get(), "idProduct"))
udev_device_unref(udevDevice);
if (id)
return id; return id;
sf::err() << "Failed to get product ID of joystick " << joystickList[index].deviceNode << std::endl; sf::err() << "Failed to get product ID of joystick " << joystickList[index].deviceNode << std::endl;
@ -412,17 +409,13 @@ std::string getJoystickName(unsigned int index)
// Fall back to manual USB chain walk via udev // Fall back to manual USB chain walk via udev
if (udevContext) if (udevContext)
{ {
udev_device* udevDevice = udev_device_new_from_syspath(udevContext, joystickList[index].systemPath.c_str()); const auto udevDevice = UdevPtr<udev_device>(
udev_device_new_from_syspath(udevContext.get(), joystickList[index].systemPath.c_str()));
if (udevDevice) if (udevDevice)
{ if (const char* product = getUsbAttribute(udevDevice.get(), "product"))
const char* product = getUsbAttribute(udevDevice, "product");
udev_device_unref(udevDevice);
if (product)
return {product}; return {product};
} }
}
sf::err() << "Unable to get name for joystick " << devnode << std::endl; sf::err() << "Unable to get name for joystick " << devnode << std::endl;
@ -436,7 +429,7 @@ namespace sf::priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void JoystickImpl::initialize() void JoystickImpl::initialize()
{ {
udevContext = udev_new(); udevContext = UdevPtr<udev>(udev_new());
if (!udevContext) if (!udevContext)
{ {
@ -444,7 +437,7 @@ void JoystickImpl::initialize()
return; return;
} }
udevMonitor = udev_monitor_new_from_netlink(udevContext, "udev"); udevMonitor = UdevPtr<udev_monitor>(udev_monitor_new_from_netlink(udevContext.get(), "udev"));
if (!udevMonitor) if (!udevMonitor)
{ {
@ -452,27 +445,25 @@ void JoystickImpl::initialize()
} }
else else
{ {
int error = udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, "input", nullptr); int error = udev_monitor_filter_add_match_subsystem_devtype(udevMonitor.get(), "input", nullptr);
if (error < 0) if (error < 0)
{ {
err() << "Failed to add udev monitor filter, joystick connections and disconnections won't be notified: " err() << "Failed to add udev monitor filter, joystick connections and disconnections won't be notified: "
<< error << std::endl; << error << std::endl;
udev_monitor_unref(udevMonitor); udevMonitor.reset();
udevMonitor = nullptr;
} }
else else
{ {
error = udev_monitor_enable_receiving(udevMonitor); error = udev_monitor_enable_receiving(udevMonitor.get());
if (error < 0) if (error < 0)
{ {
err() << "Failed to enable udev monitor, joystick connections and disconnections won't be notified: " err() << "Failed to enable udev monitor, joystick connections and disconnections won't be notified: "
<< error << std::endl; << error << std::endl;
udev_monitor_unref(udevMonitor); udevMonitor.reset();
udevMonitor = nullptr;
} }
} }
} }
@ -486,18 +477,10 @@ void JoystickImpl::initialize()
void JoystickImpl::cleanup() void JoystickImpl::cleanup()
{ {
// Unreference the udev monitor to destroy it // Unreference the udev monitor to destroy it
if (udevMonitor) udevMonitor.reset();
{
udev_monitor_unref(udevMonitor);
udevMonitor = nullptr;
}
// Unreference the udev context to destroy it // Unreference the udev context to destroy it
if (udevContext) udevContext.reset();
{
udev_unref(udevContext);
udevContext = nullptr;
}
} }
@ -513,14 +496,11 @@ bool JoystickImpl::isConnected(unsigned int index)
else if (hasMonitorEvent()) else if (hasMonitorEvent())
{ {
// Check if new joysticks were added/removed since last update // Check if new joysticks were added/removed since last update
udev_device* udevDevice = udev_monitor_receive_device(udevMonitor); const auto udevDevice = UdevPtr<udev_device>(udev_monitor_receive_device(udevMonitor.get()));
// If we can get the specific device, we check that, // If we can get the specific device, we check that,
// otherwise just do a full scan if udevDevice == nullptr // otherwise just do a full scan if udevDevice == nullptr
updatePluggedList(udevDevice); updatePluggedList(udevDevice.get());
if (udevDevice)
udev_device_unref(udevDevice);
} }
if (index >= joystickList.size()) if (index >= joystickList.size())