Skip to content

Commit e9d16ed

Browse files
committed
fix: avoid busy polling in rumble thread
fixes #2 fixes #14
1 parent 25e7525 commit e9d16ed

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

src/uhid/include/uhid/uhid.hpp

+16-15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <fcntl.h>
55
#include <functional>
66
#include <inputtino/result.hpp>
7+
#include <iostream>
78
#include <linux/uhid.h>
89
#include <memory>
910
#include <poll.h>
@@ -50,7 +51,7 @@ static inputtino::Result<bool> uhid_write(int fd, const struct uhid_event *ev) {
5051
class Device {
5152
private:
5253
Device(std::shared_ptr<std::thread> ev_thread, std::shared_ptr<ThreadState> state)
53-
: ev_thread(std::move(ev_thread)), state(std::move(state)){};
54+
: ev_thread(std::move(ev_thread)), state(std::move(state)) {};
5455
std::shared_ptr<std::thread> ev_thread;
5556
std::shared_ptr<ThreadState> state;
5657
std::shared_ptr<std::function<void(const uhid_event &ev, int fd)>> on_event;
@@ -81,7 +82,7 @@ class Device {
8182

8283
~Device() {
8384
if (state) {
84-
struct uhid_event ev {};
85+
struct uhid_event ev{};
8586
ev.type = UHID_DESTROY;
8687
uhid_write(state->fd, &ev);
8788

@@ -100,6 +101,8 @@ static void set_c_str(const std::string &str, unsigned char *c_str) {
100101
c_str[str.length()] = 0;
101102
}
102103

104+
constexpr int UHID_POLL_TIMEOUT = 500; // ms
105+
103106
inputtino::Result<Device> Device::create(const DeviceDefinition &definition,
104107
const std::function<void(const uhid_event &ev, int fd)> &on_event) {
105108

@@ -124,30 +127,28 @@ inputtino::Result<Device> Device::create(const DeviceDefinition &definition,
124127
state->fd = fd;
125128
state->on_event = on_event;
126129
auto thread = std::make_shared<std::thread>([state]() {
127-
ssize_t ret;
128-
struct pollfd pfds[1];
129-
pfds[0].fd = state->fd;
130-
pfds[0].events = POLLIN;
130+
std::array<pollfd, 1> pfds = {pollfd{.fd = state->fd, .events = POLLIN}};
131+
int poll_rs = 0;
131132

132133
while (!state->stop_repeat_thread) {
133-
ret = poll(pfds, 1, -1);
134-
if (ret < 0) {
135-
fprintf(stderr, "Cannot poll for fds: %m\n");
134+
poll_rs = poll(pfds.data(), pfds.size(), UHID_POLL_TIMEOUT);
135+
if (poll_rs < 0) {
136+
std::cerr << "Failed polling uhid fd; ret=" << strerror(errno) << std::endl;
136137
break;
137138
}
138139
if (pfds[0].revents & POLLHUP) {
139-
fprintf(stderr, "Received HUP on uhid-cdev\n");
140+
std::cerr << "HUP on uhid-cdev" << std::endl;
140141
break;
141142
}
142143
if (pfds[0].revents & POLLIN) {
143-
struct uhid_event ev {};
144-
ret = read(state->fd, &ev, sizeof(ev));
144+
struct uhid_event ev{};
145+
auto ret = read(state->fd, &ev, sizeof(ev));
145146
if (ret == 0) {
146-
fprintf(stderr, "Read HUP on uhid-cdev\n");
147+
std::cerr << "Read HUP on uhid-cdev" << std::endl;
147148
} else if (ret < 0) {
148-
fprintf(stderr, "Cannot read uhid-cdev: %m\n");
149+
std::cerr << "Cannot read uhid-cdev: " << strerror(errno) << std::endl;
149150
} else if (ret != sizeof(ev)) {
150-
fprintf(stderr, "Invalid size read from uhid-dev: %zd != %zu\n", ret, sizeof(ev));
151+
std::cerr << "Invalid size read from uhid-dev" << ret << " != " << sizeof(ev) << std::endl;
151152
} else {
152153
if (state->on_event) {
153154
state->on_event(ev, state->fd);

src/uinput/joypad_utils.hpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
#include <linux/input.h>
1111
#include <linux/uinput.h>
1212
#include <optional>
13+
#include <poll.h>
1314
#include <thread>
1415

1516
namespace inputtino {
1617

1718
using namespace std::chrono_literals;
1819

19-
static constexpr long MAX_GAIN = 0xFFFF;
20+
constexpr long MAX_GAIN = 0xFFFF;
21+
constexpr int RUMBLE_POLL_TIMEOUT = 500; // ms
2022

2123
/**
2224
* Joypads will also have one `/dev/input/js*` device as child, we want to expose that as well
@@ -165,8 +167,15 @@ static void event_listener(const std::shared_ptr<BaseJoypadState> &state) {
165167
/* This can only be set globally when receiving FF_GAIN */
166168
unsigned int current_gain = MAX_GAIN;
167169

170+
std::array<pollfd, 1> pfds = {pollfd{.fd = uinput_fd, .events = POLLIN}};
171+
int poll_rs = 0;
172+
168173
while (!state->stop_listening_events) {
169-
std::this_thread::sleep_for(20ms); // TODO: configurable?
174+
poll_rs = poll(pfds.data(), pfds.size(), RUMBLE_POLL_TIMEOUT);
175+
if (poll_rs < 0) {
176+
std::cerr << "Failed polling uinput fd; ret=" << strerror(errno);
177+
return;
178+
}
170179

171180
auto events = fetch_events(uinput_fd);
172181
for (auto ev : events) {

0 commit comments

Comments
 (0)