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>
3031usb_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
3637usb_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
252253void 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
350326void 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}
0 commit comments