aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO1
-rw-r--r--configure.ac1
-rw-r--r--examples/dpfp.c2
-rw-r--r--examples/lsusb.c7
-rw-r--r--libusb/Makefile.am2
-rw-r--r--libusb/core.c13
-rw-r--r--libusb/io.c227
-rw-r--r--libusb/libusb.h4
-rw-r--r--libusb/libusbi.h6
-rw-r--r--libusb/signalfd.h76
10 files changed, 127 insertions, 212 deletions
diff --git a/TODO b/TODO
index cc3597b..5f62598 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,5 @@
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
diff --git a/configure.ac b/configure.ac
index 660ca2a..58b4aa2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,7 @@ AC_PROG_CC
AC_PROG_LIBTOOL
AC_C_INLINE
AM_PROG_CC_C_O
+AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions])
# Library versioning
lt_major="0"
diff --git a/examples/dpfp.c b/examples/dpfp.c
index d5b0c63..d99b3af 100644
--- a/examples/dpfp.c
+++ b/examples/dpfp.c
@@ -473,7 +473,7 @@ int main(void)
struct sigaction sigact;
int r = 1;
- r = libusb_init(0);
+ r = libusb_init();
if (r < 0) {
fprintf(stderr, "failed to initialise libusb\n");
exit(1);
diff --git a/examples/lsusb.c b/examples/lsusb.c
index 8145d63..c511b29 100644
--- a/examples/lsusb.c
+++ b/examples/lsusb.c
@@ -34,7 +34,12 @@ void print_devs(libusb_dev *devs)
int main(void)
{
libusb_dev *devs;
- libusb_init(0);
+ int r;
+
+ r = libusb_init();
+ if (r < 0)
+ return r;
+
libusb_find_devices();
devs = libusb_get_devices();
diff --git a/libusb/Makefile.am b/libusb/Makefile.am
index d921468..702e702 100644
--- a/libusb/Makefile.am
+++ b/libusb/Makefile.am
@@ -1,7 +1,7 @@
lib_LTLIBRARIES = libusb-1.0.la
libusb_1_0_la_CFLAGS = -fvisibility=hidden $(AM_CFLAGS)
-libusb_1_0_la_SOURCES = signalfd.h libusbi.h usbfs.h core.c descriptor.c io.c
+libusb_1_0_la_SOURCES = libusbi.h usbfs.h core.c descriptor.c io.c
libusb_1_0_la_LIBADD = -lrt
pkginclude_HEADERS = libusb.h
diff --git a/libusb/core.c b/libusb/core.c
index 8fb8fd7..e9939f4 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -286,13 +286,14 @@ API_EXPORTED int libusb_release_interface(struct libusb_dev_handle *dev,
return r;
}
-API_EXPORTED int libusb_init(int signum)
+API_EXPORTED int libusb_init(void)
{
/* FIXME: find correct usb node path */
usbi_dbg("");
list_init(&usb_devs);
list_init(&open_devs);
- return usbi_io_init(signum);
+ usbi_io_init();
+ return 0;
}
API_EXPORTED void libusb_exit(void)
@@ -304,15 +305,13 @@ API_EXPORTED void libusb_exit(void)
list_for_each_entry(devh, &open_devs, list)
do_close(devh);
}
- 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 cnt = 0;
size_t i = 0;
/* count number of open devices */
@@ -328,10 +327,6 @@ API_EXPORTED size_t libusb_get_pollfds(struct libusb_pollfd **pollfds)
ret[i].events = POLLOUT;
}
- /* add signalfd */
- ret[i].fd = usbi_get_signalfd();
- ret[i].events = POLLIN;
-
*pollfds = ret;
return cnt;
}
diff --git a/libusb/io.c b/libusb/io.c
index 65edede..ae572ab 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -30,57 +30,17 @@
#include <time.h>
#include <unistd.h>
-/* signalfd() support is present in glibc-2.7 onwards, but glibc-2.7 contains
- * a bug where the header is neither installed or compilable. This will be
- * fixed for glibc-2.8. */
-#if __GLIBC_PREREQ(2, 8)
-#include <sys/signalfd.h>
-#else
-#include "signalfd.h"
-#endif
-
#include "libusbi.h"
-static int sigfd;
-static int signum;
-
/* this is a list of in-flight rb_handles, sorted by timeout expiration.
* URBs to timeout the soonest are placed at the beginning of the list, URBs
* that will time out later are placed after, and urbs with infinite timeout
* are always placed at the very end. */
static struct list_head flying_urbs;
-static int setup_signalfd(int _signum)
-{
- sigset_t sigset;
- if (_signum == 0)
- _signum = SIGRTMIN;
- usbi_dbg("signal %d", _signum);
-
- sigemptyset(&sigset);
- sigaddset(&sigset, _signum);
- sigfd = signalfd(-1, &sigset, 0);
- if (sigfd < 0) {
- usbi_err("signalfd failed, code=%d errno=%d", sigfd, errno);
- return sigfd;
- }
- usbi_dbg("got signalfd %d", sigfd);
- signum = _signum;
-
- sigemptyset(&sigset);
- sigaddset(&sigset, _signum);
- return sigprocmask(SIG_BLOCK, &sigset, NULL);
-}
-
-int usbi_io_init(int _signum)
+void usbi_io_init()
{
list_init(&flying_urbs);
- return setup_signalfd(signum);
-}
-
-void usbi_io_exit(void)
-{
- close(sigfd);
}
static int calculate_timeout(struct libusb_urb_handle *urbh,
@@ -88,12 +48,6 @@ static int calculate_timeout(struct libusb_urb_handle *urbh,
{
int r;
struct timespec current_time;
- struct sigevent sigevt = {
- .sigev_notify = SIGEV_SIGNAL,
- .sigev_signo = signum,
- };
- struct itimerspec itspec;
- struct timespec *it_value = &itspec.it_value;
if (!timeout)
return 0;
@@ -104,37 +58,22 @@ static int calculate_timeout(struct libusb_urb_handle *urbh,
return r;
}
- r = timer_create(CLOCK_MONOTONIC, &sigevt, &urbh->timer);
- if (r < 0) {
- usbi_err("failed to create monotonic timer");
- return r;
- }
-
- memset(&itspec, 0, sizeof(itspec));
- it_value->tv_sec = current_time.tv_sec + (timeout / 1000);
- it_value->tv_nsec = current_time.tv_nsec +
- ((timeout % 1000) * 1000000);
-
- if (it_value->tv_nsec > 1000000000) {
- it_value->tv_nsec -= 1000000000;
- it_value->tv_sec++;
- }
+ current_time.tv_sec += timeout / 1000;
+ current_time.tv_nsec += (timeout % 1000) * 1000000;
- r = timer_settime(&urbh->timer, TIMER_ABSTIME, &itspec, NULL);
- if (r < 0) {
- usbi_err("failed to arm monotonic timer");
- return r;
+ if (current_time.tv_nsec > 1000000000) {
+ current_time.tv_nsec -= 1000000000;
+ current_time.tv_sec++;
}
- urbh->timeout = itspec.it_value;
-
+ TIMESPEC_TO_TIMEVAL(&urbh->timeout, &current_time);
return 0;
}
static void add_to_flying_list(struct libusb_urb_handle *urbh)
{
struct libusb_urb_handle *cur;
- struct timespec *timeout = &urbh->timeout;
+ struct timeval *timeout = &urbh->timeout;
/* if we have no other flying urbs, start the list with this one */
if (list_empty(&flying_urbs)) {
@@ -143,7 +82,7 @@ static void add_to_flying_list(struct libusb_urb_handle *urbh)
}
/* if we have infinite timeout, append to end of list */
- if (!TIMESPEC_IS_SET(timeout)) {
+ if (!timerisset(timeout)) {
list_add_tail(&urbh->list, &flying_urbs);
return;
}
@@ -151,11 +90,11 @@ static void add_to_flying_list(struct libusb_urb_handle *urbh)
/* otherwise, find appropriate place in list */
list_for_each_entry(cur, &flying_urbs, list) {
/* find first timeout that occurs after the urbh in question */
- struct timespec *cur_ts = &cur->timeout;
+ struct timeval *cur_tv = &cur->timeout;
- if (!TIMESPEC_IS_SET(cur_ts) || (cur_ts->tv_sec > timeout->tv_sec) ||
- (cur_ts->tv_sec == timeout->tv_sec &&
- cur_ts->tv_nsec > timeout->tv_nsec)) {
+ if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) ||
+ (cur_tv->tv_sec == timeout->tv_sec &&
+ cur_tv->tv_usec > timeout->tv_usec)) {
list_add_tail(&urbh->list, &cur->list);
return;
}
@@ -341,9 +280,6 @@ int handle_transfer_completion(struct libusb_dev_handle *devh,
{
struct usb_urb *urb = &urbh->urb;
- if (TIMESPEC_IS_SET(&urbh->timeout))
- timer_delete(urbh->timer);
-
if (status == FP_URB_SILENT_COMPLETION)
return 0;
@@ -457,7 +393,8 @@ static void handle_timeout(struct libusb_urb_handle *urbh)
static int handle_timeouts(void)
{
- struct timespec systime;
+ struct timespec systime_ts;
+ struct timeval systime;
struct libusb_urb_handle *urbh;
int r;
@@ -465,23 +402,29 @@ static int handle_timeouts(void)
return 0;
/* get current time */
- r = clock_gettime(CLOCK_MONOTONIC, &systime);
+ r = clock_gettime(CLOCK_MONOTONIC, &systime_ts);
if (r < 0)
return r;
+ TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
+
/* iterate through flying urbs list, finding all urbs that have expired
* timeouts */
list_for_each_entry(urbh, &flying_urbs, list) {
- struct timespec *cur_ts = &urbh->timeout;
+ struct timeval *cur_tv = &urbh->timeout;
/* if we've reached urbs of infinite timeout, we're all done */
- if (!TIMESPEC_IS_SET(cur_ts))
+ if (!timerisset(cur_tv))
return 0;
+ /* ignore timeouts we've already handled */
+ if (urbh->flags & LIBUSB_URBH_TIMED_OUT)
+ continue;
+
/* if urb has non-expired timeout, nothing more to do */
- if ((cur_ts->tv_sec > systime.tv_sec) ||
- (cur_ts->tv_sec == systime.tv_sec &&
- cur_ts->tv_nsec > systime.tv_nsec))
+ if ((cur_tv->tv_sec > systime.tv_sec) ||
+ (cur_tv->tv_sec == systime.tv_sec &&
+ cur_tv->tv_usec > systime.tv_usec))
return 0;
/* otherwise, we've got an expired timeout to handle */
@@ -491,32 +434,29 @@ static int handle_timeouts(void)
return 0;
}
-static int flush_sigfd(void)
-{
- int r;
- struct signalfd_siginfo siginfo;
- r = read(sigfd, &siginfo, sizeof(siginfo));
- if (r < 0) {
- usbi_err("sigfd read failed %d %d", r, errno);
- return r;
- }
- if ((unsigned int) r < sizeof(siginfo)) {
- usbi_err("sigfd short read (%d/%d)", r, sizeof(siginfo));
- return -1;
- }
- return 0;
-}
-
static int poll_io(struct timeval *tv)
{
struct libusb_dev_handle *devh;
int r;
- int maxfd = sigfd;
- fd_set readfds;
+ int maxfd = 0;
fd_set writefds;
+ struct timeval select_timeout;
+ struct timeval timeout;
- FD_ZERO(&readfds);
- FD_SET(sigfd, &readfds);
+ r = libusb_get_next_timeout(&timeout);
+ if (r) {
+ /* timeout already expired? */
+ if (!timerisset(&timeout))
+ return handle_timeouts();
+
+ /* choose the smallest of next URB timeout or user specified timeout */
+ if (timercmp(&timeout, tv, <))
+ select_timeout = timeout;
+ else
+ select_timeout = *tv;
+ } else {
+ select_timeout = *tv;
+ }
FD_ZERO(&writefds);
list_for_each_entry(devh, &open_devs, list) {
@@ -526,17 +466,21 @@ static int poll_io(struct timeval *tv)
maxfd = fd;
}
- r = select(maxfd + 1, &readfds, &writefds, NULL, tv);
- if (r == 0 || (r == -1 && errno == EINTR)) {
+ usbi_dbg("select() with timeout in %d.%06ds", select_timeout.tv_sec,
+ select_timeout.tv_usec);
+ r = select(maxfd + 1, NULL, &writefds, NULL, &select_timeout);
+ usbi_dbg("select() returned %d with %d.%06ds remaining", r, select_timeout.tv_sec,
+ select_timeout.tv_usec);
+ if (r == 0) {
+ *tv = select_timeout;
+ return handle_timeouts();
+ } else if (r == -1 && errno == EINTR) {
return 0;
} else if (r < 0) {
usbi_err("select failed %d err=%d\n", r, errno);
return r;
}
- if (FD_ISSET(sigfd, &readfds))
- flush_sigfd();
-
list_for_each_entry(devh, &open_devs, list) {
if (!FD_ISSET(devh->fd, &writefds))
continue;
@@ -548,8 +492,7 @@ static int poll_io(struct timeval *tv)
}
/* FIXME check return value? */
- handle_timeouts();
- return 0;
+ return handle_timeouts();
}
API_EXPORTED int libusb_poll_timeout(struct timeval *tv)
@@ -560,11 +503,64 @@ API_EXPORTED int libusb_poll_timeout(struct timeval *tv)
API_EXPORTED int libusb_poll(void)
{
struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 500000;
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
return poll_io(&tv);
}
+API_EXPORTED int libusb_get_next_timeout(struct timeval *tv)
+{
+ struct libusb_urb_handle *urbh;
+ struct timespec cur_ts;
+ struct timeval cur_tv;
+ struct timeval *next_timeout;
+ int r;
+ int found = 0;
+
+ if (list_empty(&flying_urbs)) {
+ usbi_dbg("no URBs, no timeout!");
+ return 0;
+ }
+
+ /* find next urb which hasn't already been processed as timed out */
+ list_for_each_entry(urbh, &flying_urbs, list) {
+ if (!(urbh->flags & LIBUSB_URBH_TIMED_OUT)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ usbi_dbg("all URBs have already been processed for timeouts");
+ return 0;
+ }
+
+ next_timeout = &urbh->timeout;
+
+ /* no timeout for next urb */
+ if (!timerisset(next_timeout)) {
+ usbi_dbg("no URBs with timeouts, no timeout!");
+ return 0;
+ }
+
+ r = clock_gettime(CLOCK_MONOTONIC, &cur_ts);
+ if (r < 0) {
+ usbi_err("failed to read monotonic clock, errno=%d", errno);
+ return r;
+ }
+ TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
+
+ if (timercmp(&cur_tv, next_timeout, >=)) {
+ usbi_dbg("first timeout already expired");
+ timerclear(tv);
+ } else {
+ timersub(next_timeout, &cur_tv, tv);
+ usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
+ }
+
+ return 1;
+}
+
struct sync_ctrl_handle {
enum libusb_urb_cb_status status;
unsigned char *data;
@@ -705,8 +701,3 @@ API_EXPORTED void libusb_urb_handle_free(struct libusb_urb_handle *urbh)
free(urbh);
}
-int usbi_get_signalfd(void)
-{
- return sigfd;
-}
-
diff --git a/libusb/libusb.h b/libusb/libusb.h
index 1358680..b07314e 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -23,6 +23,7 @@
#include <stdint.h>
#include <sys/time.h>
+#include <time.h>
#ifdef __cplusplus
extern "C" {
@@ -218,7 +219,7 @@ typedef void (*libusb_bulk_cb_fn)(libusb_dev_handle *devh, libusb_urb_handle *ur
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data);
-int libusb_init(int signum);
+int libusb_init(void);
void libusb_exit(void);
int libusb_find_devices(void);
@@ -257,6 +258,7 @@ void libusb_urb_handle_free(libusb_urb_handle *urbh);
int libusb_poll_timeout(struct timeval *tv);
int libusb_poll(void);
+int libusb_get_next_timeout(struct timeval *tv);
size_t libusb_get_pollfds(struct libusb_pollfd **pollfds);
/* sync I/O */
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 0ff4962..127990f 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -169,8 +169,7 @@ struct libusb_urb_handle {
struct libusb_dev_handle *devh;
struct usb_urb urb;
struct list_head list;
- struct timespec timeout;
- timer_t timer;
+ struct timeval timeout;
unsigned char urb_type;
unsigned char endpoint;
int transfer_len;
@@ -193,8 +192,7 @@ struct usb_descriptor_header {
extern struct list_head open_devs;
-int usbi_io_init(int _signum);
-void usbi_io_exit(void);
+void usbi_io_init(void);
int usbi_parse_descriptor(unsigned char *source, char *descriptor, void *dest);
int usbi_parse_configuration(struct libusb_config_descriptor *config,
diff --git a/libusb/signalfd.h b/libusb/signalfd.h
deleted file mode 100644
index e96d693..0000000
--- a/libusb/signalfd.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * signalfd header
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
- *
- * Based on glibc header
- * Copyright (C) 2007 Free Software Foundation, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef __LIBUSB_SIGNALFD_H__
-#define __LIBUSB_SIGNALFD_H__
-
-/* FIXME: in future, remove this and unconditionally use glibc directly when
- * glibc-2.8 is widespread */
-
-#include <signal.h>
-#include <stdint.h>
-
-#ifdef __i386__
-#define __NR_signalfd 321
-#elif defined(__x86_64__)
-#define __NR_signalfd 282
-#else
-#error "signalfd unsupported on this architecture"
-#endif
-
-/* signalfd() implementation was added as of glibc-2.7 */
-#if __GLIBC_PREREQ(2, 7)
-int signalfd(int fd, const sigset_t *mask, int flags);
-#else
-#include <sys/syscall.h>
-
-#define SIZEOF_SIG (_NSIG / 8)
-#define SIZEOF_SIGSET (SIZEOF_SIG > sizeof(sigset_t) ? sizeof(sigset_t): SIZEOF_SIG)
-
-static inline int signalfd(int fd, const sigset_t *mask, int flags)
-{
- return syscall(__NR_signalfd, fd, mask, SIZEOF_SIGSET);
-}
-#endif
-
-struct signalfd_siginfo {
- uint32_t ssi_signo;
- int32_t ssi_errno;
- int32_t ssi_code;
- uint32_t ssi_pid;
- uint32_t ssi_uid;
- int32_t ssi_fd;
- uint32_t ssi_tid;
- uint32_t ssi_band;
- uint32_t ssi_overrun;
- uint32_t ssi_trapno;
- int32_t ssi_status;
- int32_t ssi_int;
- uint64_t ssi_ptr;
- uint64_t ssi_utime;
- uint64_t ssi_stime;
- uint64_t ssi_addr;
- uint8_t __pad[48];
-};
-
-#endif
-