Poll usbfs descriptors directly
authorDaniel Drake <dsd@gentoo.org>
Sat, 26 Jan 2008 18:16:56 +0000 (18:16 +0000)
committerDaniel Drake <dsd@gentoo.org>
Sat, 26 Jan 2008 18:19:04 +0000 (18:19 +0000)
We don't need to use signalfd for this functionality because we can poll
the file descriptors for write events.

TODO
libusb/core.c
libusb/io.c
libusb/libusb.h

diff --git a/TODO b/TODO
index f4becf6..cc3597b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,10 +1,9 @@
 isochronous endpoint I/O
 optional timerfd support (runtime detection)
+timer (call me back in 2 seconds) implementation (then remove signalfd)
 API docs
 notifications of hotplugged/unplugged devices
 thread safety
-signalfd emulation through pipes and sigaction() for older kernels
-signalfd not needed for usbfs? can we poll on the fd?
 use poll() rather than select()?
 abstraction for cross-platform-ness
 
index 9fca011..8fb8fd7 100644 (file)
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <features.h>
+#include <poll.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -306,6 +307,35 @@ API_EXPORTED void libusb_exit(void)
        usbi_io_exit();
 }
 
+API_EXPORTED size_t libusb_get_pollfds(struct libusb_pollfd **pollfds)
+{
+       struct libusb_dev_handle *devh;
+       struct libusb_pollfd *ret;
+       /* initialise to 1 for signalfd */
+       size_t cnt = 1;
+       size_t i = 0;
+
+       /* count number of open devices */
+       list_for_each_entry(devh, &open_devs, list)
+               cnt++;
+
+       /* create array */
+       ret = calloc(cnt, sizeof(struct libusb_pollfd));
+
+       /* add fds */
+       list_for_each_entry(devh, &open_devs, list) {
+               ret[i++].fd = devh->fd;
+               ret[i].events = POLLOUT;
+       }
+       
+       /* add signalfd */
+       ret[i].fd = usbi_get_signalfd();
+       ret[i].events = POLLIN;
+
+       *pollfds = ret;
+       return cnt;
+}
+
 void usbi_log(enum usbi_log_level level, const char *function,
        const char *format, ...)
 {
index 06b7666..65edede 100644 (file)
@@ -176,7 +176,6 @@ static int submit_urb(struct libusb_dev_handle *devh,
        urb->endpoint = urbh->endpoint;
        urb->buffer = urbh->buffer + urbh->transferred;
        urb->buffer_length = MIN(to_be_transferred, MAX_URB_BUFFER_LENGTH);
-       urb->signr = signum;
 
        /* FIXME: for requests that we have to split into multiple URBs, we should
         * submit all the URBs instantly: submit, submit, submit, reap, reap, reap
@@ -492,24 +491,6 @@ static int handle_timeouts(void)
        return 0;
 }
 
-static int reap(void)
-{
-       struct libusb_dev_handle *devh;
-       int r;
-
-       list_for_each_entry(devh, &open_devs, list) {
-               r = reap_for_devh(devh);
-               if (r == -1 && errno == EAGAIN)
-                       continue;
-               if (r < 0)
-                       return r;
-       }
-
-       r = handle_timeouts();
-
-       return 0;
-}
-
 static int flush_sigfd(void)
 {
        int r;
@@ -528,24 +509,46 @@ static int flush_sigfd(void)
 
 static int poll_io(struct timeval *tv)
 {
+       struct libusb_dev_handle *devh;
        int r;
-       fd_set fds;
+       int maxfd = sigfd;
+       fd_set readfds;
+       fd_set writefds;
+
+       FD_ZERO(&readfds);
+       FD_SET(sigfd, &readfds);
+
+       FD_ZERO(&writefds);
+       list_for_each_entry(devh, &open_devs, list) {
+               int fd = devh->fd;
+               FD_SET(fd, &writefds);
+               if (fd > maxfd)
+                       maxfd = fd;
+       }
 
-       FD_ZERO(&fds);
-       FD_SET(sigfd, &fds);
-       r = select(sigfd + 1, &fds, NULL, NULL, tv);
-       if (r == -1 && errno == EINTR)
+       r = select(maxfd + 1, &readfds, &writefds, NULL, tv);
+       if (r == 0 || (r == -1 && errno == EINTR)) {
                return 0;
-       if (r < 0) {
+       } else if (r < 0) {
                usbi_err("select failed %d err=%d\n", r, errno);
                return r;
        }
 
-       if (r > 0) {
+       if (FD_ISSET(sigfd, &readfds))
                flush_sigfd();
-               return reap();
+
+       list_for_each_entry(devh, &open_devs, list) {
+               if (!FD_ISSET(devh->fd, &writefds))
+                       continue;
+               r = reap_for_devh(devh);
+               if (r == -1 && errno == EAGAIN)
+                       continue;
+               if (r < 0)
+                       return r;
        }
 
+       /* FIXME check return value? */
+       handle_timeouts();
        return 0;
 }
 
@@ -702,7 +705,7 @@ API_EXPORTED void libusb_urb_handle_free(struct libusb_urb_handle *urbh)
        free(urbh);
 }
 
-API_EXPORTED int libusb_get_pollfd(void)
+int usbi_get_signalfd(void)
 {
        return sigfd;
 }
index bff48f2..1358680 100644 (file)
@@ -235,6 +235,11 @@ int libusb_release_interface(libusb_dev_handle *dev, int iface);
 
 /* async I/O */
 
+struct libusb_pollfd {
+       int fd;
+       short events;
+};
+
 libusb_urb_handle *libusb_async_control_transfer(libusb_dev_handle *devh,
        struct libusb_control_transfer *transfer, libusb_ctrl_cb_fn callback,
        void *user_data, unsigned int timeout);
@@ -252,7 +257,7 @@ void libusb_urb_handle_free(libusb_urb_handle *urbh);
 
 int libusb_poll_timeout(struct timeval *tv);
 int libusb_poll(void);
-int libusb_get_pollfd(void);
+size_t libusb_get_pollfds(struct libusb_pollfd **pollfds);
 
 /* sync I/O */