Skip to content

Commit fc4cee8

Browse files
committed
Linux reference code: epoll instead of poll
1 parent 8cb47de commit fc4cee8

File tree

3 files changed

+62
-103
lines changed

3 files changed

+62
-103
lines changed

reference/linux/usb_device.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,6 @@ void usb_device::submit_urb(usbdevfs_urb* urb) {
314314

315315
void usb_device::cancel_urb(usbdevfs_urb* urb) {
316316
int result = ioctl(fd_, USBDEVFS_DISCARDURB, urb);
317-
if (result < 0)
318-
usb_error::throw_error("Failed to submit URB");
317+
if (result < 0 && errno != EINVAL)
318+
usb_error::throw_error("Failed to cancel URB");
319319
}

reference/linux/usb_registry.cpp

Lines changed: 57 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <libudev.h>
1616
#include <poll.h>
17+
#include <sys/epoll.h>
1718
#include <unistd.h>
1819
#include <sys/eventfd.h>
1920
#include <linux/usbdevice_fs.h>
@@ -30,18 +31,18 @@
3031
usb_registry::usb_registry()
3132
: monitor_wake_event_fd(-1),
3233
on_connected_callback(nullptr), on_disconnected_callback(nullptr), is_device_list_ready(false),
33-
async_io_update_event_fd(-1), async_io_update_request(0), async_io_update_response(0) {
34+
async_io_epoll_fd(-1), async_io_exit_event_fd(-1) {
3435
}
3536

3637
usb_registry::~usb_registry() {
3738
eventfd_write(monitor_wake_event_fd, 1);
3839
monitor_thread.join();
3940
::close(monitor_wake_event_fd);
4041

41-
if (async_io_update_event_fd != -1) {
42-
eventfd_write(async_io_update_event_fd, 999999);
42+
if (async_io_exit_event_fd != -1) {
43+
eventfd_write(async_io_exit_event_fd, 999999);
4344
async_io_thread.join();
44-
::close(async_io_update_event_fd);
45+
::close(async_io_exit_event_fd);
4546
}
4647
}
4748

@@ -251,66 +252,38 @@ std::shared_ptr<usb_device> usb_registry::get_shared_ptr(usb_device* device) {
251252

252253
void usb_registry::async_io_run() {
253254

254-
{
255-
std::lock_guard lock(async_io_mutex);
256-
async_io_update_response = async_io_update_request;
257-
async_io_condition.notify_all();
258-
}
259-
260-
std::vector<pollfd> fds;
261-
fds.resize(2);
262-
fds[0].fd = async_io_update_event_fd;
263-
fds[0].events = POLLIN;
264-
265255
while (true) {
266-
267-
int num_fds = 1;
268-
fds.resize(async_io_fds.size() + 1);
269-
270-
{
271-
std::lock_guard lock(async_io_mutex);
272-
for (auto fd : async_io_fds) {
273-
fds[num_fds].fd = fd;
274-
fds[num_fds].events = POLLIN | POLLOUT;
275-
num_fds += 1;
276-
}
277-
}
278-
279-
int ret = poll(fds.data(), num_fds, -1);
280-
if (ret < 0)
281-
usb_error::throw_error("internal error (poll)");
282-
283-
for (auto it = fds.begin(); it != fds.end(); ++it) {
284-
if (it->revents == 0)
256+
struct epoll_event events[5];
257+
int ret = epoll_wait(async_io_epoll_fd, &events[0], 5, -1);
258+
if (ret < 0) {
259+
if (errno == EINTR)
285260
continue;
261+
usb_error::throw_error("internal error (epoll)");
262+
}
263+
264+
for (int i = 0; i < ret; i++) {
265+
int fd = events[i].data.fd;
266+
if (fd == async_io_exit_event_fd)
267+
return;
268+
reap_urbs(fd);
269+
}
270+
}
271+
}
286272

287-
if (it->fd == async_io_update_event_fd) {
288-
eventfd_t value = 0;
289-
eventfd_read(async_io_update_event_fd, &value);
290-
if (value >= 999999)
291-
return;
292-
293-
std::lock_guard lock(async_io_mutex);
294-
async_io_update_response = async_io_update_request;
295-
async_io_condition.notify_all();
296-
continue;
297-
}
298-
299-
if ((it->revents & POLLERR) != 0) {
300-
// TODO
301-
continue;
302-
}
303-
304-
if (it->revents != 0) {
305-
usbdevfs_urb* urb = nullptr;
306-
ret = ioctl(it->fd, USBDEVFS_REAPURB, &urb);
307-
if (ret < 0)
308-
usb_error::throw_error("internal error (reap URB)");
309-
310-
auto completion = reinterpret_cast<usb_io_callback*>(urb->usercontext);
311-
(*completion)();
312-
}
273+
void usb_registry::reap_urbs(int fd) {
274+
while (true) {
275+
usbdevfs_urb* urb = nullptr;
276+
int ret = ioctl(fd, USBDEVFS_REAPURB, &urb);
277+
if (ret < 0) {
278+
if (errno == EAGAIN)
279+
return; // no more pending URBs
280+
if (errno == ENODEV)
281+
return; // ignore, device might have been closed
282+
usb_error::throw_error("internal error (reap URB)");
313283
}
284+
285+
auto completion = reinterpret_cast<usb_io_callback*>(urb->usercontext);
286+
(*completion)();
314287
}
315288
}
316289

@@ -321,50 +294,38 @@ void usb_registry::add_async_fd(int fd) {
321294
std::lock_guard lock(async_io_mutex);
322295

323296
// start background thread if needed
324-
if (async_io_update_event_fd == -1) {
325-
async_io_update_event_fd = eventfd(0, 0);
326-
if (async_io_update_event_fd < 0)
297+
if (async_io_exit_event_fd == -1) {
298+
async_io_exit_event_fd = eventfd(0, 0);
299+
if (async_io_exit_event_fd < 0)
327300
usb_error::throw_error("internal error(eventfd)");
328301

329-
async_io_thread = std::thread(&usb_registry::async_io_run, this);
330-
}
331-
332-
if (std::find(async_io_fds.begin(), async_io_fds.end(), fd) != async_io_fds.end())
333-
return; // already registered
302+
async_io_epoll_fd = epoll_create(4);
303+
if (async_io_epoll_fd < 0)
304+
usb_error::throw_error("internal error(epoll_create)");
334305

335-
async_io_fds.emplace_back(fd);
336-
eventfd_write(async_io_update_event_fd, 1);
306+
epoll_event event = {0};
307+
event.events = EPOLLIN;
308+
event.data.fd = async_io_exit_event_fd;
309+
int ret = epoll_ctl(async_io_epoll_fd, EPOLL_CTL_ADD, async_io_exit_event_fd, &event);
310+
if (ret < 0)
311+
usb_error::throw_error("internal error(epoll_ctl)");
337312

338-
async_io_update_request += 1;
339-
expected_request = async_io_update_request;
313+
async_io_thread = std::thread(&usb_registry::async_io_run, this);
314+
}
340315
}
341316

342-
// wait for background process to add file descriptor for polling
343-
{
344-
std::unique_lock wait_lock(async_io_mutex);
345-
async_io_condition.wait(wait_lock, [this, expected_request] { return expected_request - async_io_update_response <= 0; });
346-
}
317+
epoll_event event = {0};
318+
event.events = EPOLLOUT;
319+
event.data.fd = fd;
320+
int ret = epoll_ctl(async_io_epoll_fd, EPOLL_CTL_ADD, fd, &event);
321+
if (ret < 0)
322+
usb_error::throw_error("internal error(epoll_ctl)");
347323
}
348324

349325

350326
void usb_registry::remove_async_fd(int fd) {
351-
int expected_request;
352-
353-
{
354-
std::lock_guard lock(async_io_mutex);
355-
356-
async_io_fds.erase(
357-
std::remove(async_io_fds.begin(), async_io_fds.end(), fd),
358-
async_io_fds.end()
359-
);
360-
async_io_update_request += 1;
361-
expected_request = async_io_update_request;
362-
eventfd_write(async_io_update_event_fd, 1);
363-
}
364-
365-
// wait for background process to remove file descriptor from polling
366-
{
367-
std::unique_lock wait_lock(async_io_mutex);
368-
async_io_condition.wait(wait_lock, [this, expected_request] { return expected_request - async_io_update_response <= 0; });
369-
}
327+
epoll_event event = {0};
328+
int ret = epoll_ctl(async_io_epoll_fd, EPOLL_CTL_DEL, fd, &event);
329+
if (ret < 0)
330+
usb_error::throw_error("internal error(epoll_ctl)");
370331
}

reference/linux/usb_registry.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class usb_registry {
5252
void async_io_run();
5353
void add_async_fd(int fd);
5454
void remove_async_fd(int fd);
55+
void reap_urbs(int fd);
5556

5657
std::shared_ptr<usb_device> create_device(udev_device* udev_dev);
5758
std::shared_ptr<usb_device> get_shared_ptr(usb_device* device);
@@ -69,11 +70,8 @@ class usb_registry {
6970

7071
std::thread async_io_thread;
7172
std::mutex async_io_mutex;
72-
std::condition_variable async_io_condition;
73-
std::vector<int> async_io_fds;
74-
int async_io_update_event_fd;
75-
int async_io_update_request;
76-
int async_io_update_response;
73+
int async_io_epoll_fd;
74+
int async_io_exit_event_fd;
7775

7876
friend usb_device;
7977
};

0 commit comments

Comments
 (0)