Skip to content

Commit

Permalink
evdev: close file descriptors in a separate thread
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Tilka committed Apr 6, 2024
1 parent d307335 commit 0aaf11e
Showing 1 changed file with 13 additions and 3 deletions.
16 changes: 13 additions & 3 deletions Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
Expand Up @@ -8,6 +8,7 @@
#include <map>
#include <memory>
#include <string>
#include <vector>

#include <fcntl.h>
#include <libudev.h>
Expand All @@ -21,6 +22,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
Expand All @@ -34,6 +36,12 @@ class InputBackend final : public ciface::InputBackend

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);
Expand All @@ -55,6 +63,8 @@ class InputBackend final : public ciface::InputBackend
// 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)
Expand Down Expand Up @@ -273,7 +283,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;
}

Expand Down Expand Up @@ -415,7 +425,7 @@ void InputBackend::StopHotplugThread()
}

InputBackend::InputBackend(ControllerInterface* controller_interface)
: ciface::InputBackend(controller_interface)
: ciface::InputBackend(controller_interface), m_cleanup_thread("evdev cleanup", close)
{
StartHotplugThread();
}
Expand Down Expand Up @@ -665,7 +675,7 @@ evdevDevice::~evdevDevice()
{
m_input_backend.RemoveDevnodeObject(node.devnode);
libevdev_free(node.device);
close(node.fd);
m_input_backend.CloseDescriptor(node.fd);
}
}

Expand Down

0 comments on commit 0aaf11e

Please sign in to comment.