evdev: close file descriptors in a separate thread

For some reason Linux is surprisingly slow at closing file descriptors
of event devices. This commit improves GUI startup times on my computer
by about 1.5 seconds.
This commit is contained in:
Tillmann Karras 2023-11-28 13:25:59 +00:00
parent 116da3ab95
commit d1db347c8a
1 changed files with 12 additions and 3 deletions

View File

@ -21,6 +21,7 @@
#include "Common/ScopeGuard.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h"
#include "Common/WorkQueueThread.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
namespace ciface::evdev
@ -34,6 +35,12 @@ public:
void RemoveDevnodeObject(const std::string&);
// Linux has the strange behavior that closing file descriptors of event devices can be
// surprisingly slow, in the range of 20-70 milliseconds. For modern systems that have maybe 30
// event devices this can quickly add up, leading to visibly slow startup. So we close FDs on a
// separate thread *shrug*
void CloseDescriptor(int fd) { m_cleanup_thread.Push(fd); }
private:
std::shared_ptr<evdevDevice>
FindDeviceWithUniqueIDAndPhysicalLocation(const char* unique_id, const char* physical_location);
@ -55,6 +62,8 @@ private:
// as devices can be destroyed by any thread at any time. As of now it's protected
// by ControllerInterface::m_devices_population_mutex.
std::map<std::string, std::weak_ptr<evdevDevice>> m_devnode_objects;
Common::WorkQueueThread<int> m_cleanup_thread;
};
std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
@ -273,7 +282,7 @@ void InputBackend::AddDeviceNode(const char* devnode)
if (libevdev_new_from_fd(fd, &dev) != 0)
{
// This usually fails because the device node isn't an evdev device, such as /dev/input/js0
close(fd);
CloseDescriptor(fd);
return;
}
@ -415,7 +424,7 @@ void InputBackend::StopHotplugThread()
}
InputBackend::InputBackend(ControllerInterface* controller_interface)
: ciface::InputBackend(controller_interface)
: ciface::InputBackend(controller_interface), m_cleanup_thread("evdev cleanup", close)
{
StartHotplugThread();
}
@ -665,7 +674,7 @@ evdevDevice::~evdevDevice()
{
m_input_backend.RemoveDevnodeObject(node.devnode);
libevdev_free(node.device);
close(node.fd);
m_input_backend.CloseDescriptor(node.fd);
}
}