mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-06 03:18:13 +00:00
udev: Fix O(n^2) device walking issue (closes #9092)
I believe there was a O(n^2) device walking issues on startup
- MaybeAddDevice gets called for every device at startup
- MaybeAddDevice calls IsJoystick
- IsJoystick calls SDL_UDEV_GetProductInfo
- SDL_UDEV_GetProductInfo calls udev_enumerate_scan_devices
- udev_enumerate_scan_devices walks all the devices
Prior to commit 3b1e0e1
this was mostly masked as IsJoystick only
called SDL_UDEV_GetProductInfo when a JSIOCGNAME ioctl was
successful. This fixes the O(n^2) behaviour by directly getting
the device via udev_device_new_from_devnum (based on type, major,
and minor number) instead of enumerating everything via
udev_enumerate_scan_devices and matching on name.
This commit is contained in:

committed by
Sam Lantinga

parent
6ba3e56538
commit
6e1611cc77
@@ -31,6 +31,7 @@
|
|||||||
#ifdef SDL_USE_LIBUDEV
|
#ifdef SDL_USE_LIBUDEV
|
||||||
|
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "SDL_assert.h"
|
#include "SDL_assert.h"
|
||||||
#include "SDL_evdev_capabilities.h"
|
#include "SDL_evdev_capabilities.h"
|
||||||
@@ -227,61 +228,59 @@ void SDL_UDEV_Scan(void)
|
|||||||
|
|
||||||
SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class)
|
SDL_bool SDL_UDEV_GetProductInfo(const char *device_path, Uint16 *vendor, Uint16 *product, Uint16 *version, int *class)
|
||||||
{
|
{
|
||||||
struct udev_enumerate *enumerate = NULL;
|
struct stat statbuf;
|
||||||
struct udev_list_entry *devs = NULL;
|
char type;
|
||||||
struct udev_list_entry *item = NULL;
|
struct udev_device *dev;
|
||||||
SDL_bool found = SDL_FALSE;
|
const char* val;
|
||||||
|
int class_temp;
|
||||||
|
|
||||||
if (!_this) {
|
if (!_this) {
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enumerate = _this->syms.udev_enumerate_new(_this->udev);
|
if (stat(device_path, &statbuf) == -1) {
|
||||||
if (!enumerate) {
|
|
||||||
SDL_SetError("udev_enumerate_new() failed");
|
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->syms.udev_enumerate_scan_devices(enumerate);
|
if (S_ISBLK(statbuf.st_mode)) {
|
||||||
devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
|
type = 'b';
|
||||||
for (item = devs; item && !found; item = _this->syms.udev_list_entry_get_next(item)) {
|
}
|
||||||
const char *path = _this->syms.udev_list_entry_get_name(item);
|
else if (S_ISCHR(statbuf.st_mode)) {
|
||||||
struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path);
|
type = 'c';
|
||||||
if (dev) {
|
}
|
||||||
const char *val = NULL;
|
else {
|
||||||
const char *existing_path;
|
return SDL_FALSE;
|
||||||
|
|
||||||
existing_path = _this->syms.udev_device_get_devnode(dev);
|
|
||||||
if (existing_path && SDL_strcmp(device_path, existing_path) == 0) {
|
|
||||||
int class_temp;
|
|
||||||
found = SDL_TRUE;
|
|
||||||
|
|
||||||
val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID");
|
|
||||||
if (val) {
|
|
||||||
*vendor = (Uint16)SDL_strtol(val, NULL, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
val = _this->syms.udev_device_get_property_value(dev, "ID_MODEL_ID");
|
|
||||||
if (val) {
|
|
||||||
*product = (Uint16)SDL_strtol(val, NULL, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
val = _this->syms.udev_device_get_property_value(dev, "ID_REVISION");
|
|
||||||
if (val) {
|
|
||||||
*version = (Uint16)SDL_strtol(val, NULL, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
class_temp = device_class(dev);
|
|
||||||
if (class_temp) {
|
|
||||||
*class = class_temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_this->syms.udev_device_unref(dev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_this->syms.udev_enumerate_unref(enumerate);
|
|
||||||
|
|
||||||
return found;
|
dev = _this->syms.udev_device_new_from_devnum(_this->udev, type, statbuf.st_rdev);
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = _this->syms.udev_device_get_property_value(dev, "ID_VENDOR_ID");
|
||||||
|
if (val) {
|
||||||
|
*vendor = (Uint16)SDL_strtol(val, NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = _this->syms.udev_device_get_property_value(dev, "ID_MODEL_ID");
|
||||||
|
if (val) {
|
||||||
|
*product = (Uint16)SDL_strtol(val, NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = _this->syms.udev_device_get_property_value(dev, "ID_REVISION");
|
||||||
|
if (val) {
|
||||||
|
*version = (Uint16)SDL_strtol(val, NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
class_temp = device_class(dev);
|
||||||
|
if (class_temp) {
|
||||||
|
*class = class_temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
_this->syms.udev_device_unref(dev);
|
||||||
|
|
||||||
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL_UDEV_UnloadLibrary(void)
|
void SDL_UDEV_UnloadLibrary(void)
|
||||||
|
Reference in New Issue
Block a user