summaryrefslogtreecommitdiff
path: root/libusb/os/linux_usbfs.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2009-09-11 22:09:12 +0100
committerDaniel Drake <dsd@gentoo.org>2009-09-11 22:12:27 +0100
commit858684f0dd25921e09565034a88709dbf6f6c61b (patch)
treee45921eef51c4083197ba2cdc176e17f8d2f1cfa /libusb/os/linux_usbfs.c
parentfe0d8dce1ed704915d501e7da700440c78144211 (diff)
downloadlibusb-858684f0dd25921e09565034a88709dbf6f6c61b.tar.gz
Linux: more flexibility with monotonic clock
Some users have reported that CLOCK_MONOTONIC does not work on their systems - I suspect it is available on x86 but perhaps not some of the more uncommon architectures. We should fall back on CLOCK_REALTIME in these cases. Also, CLOCK_MONOTONIC_RAW seems even more monotonic, so we should use that if it is available. We now test different clock IDs during initialization to find the best one that works.
Diffstat (limited to 'libusb/os/linux_usbfs.c')
-rw-r--r--libusb/os/linux_usbfs.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 1280188..bffd780 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -1,6 +1,6 @@
/*
* Linux usbfs backend for libusb
- * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
*
* This library is free software; you can redistribute it and/or
@@ -71,6 +71,10 @@
static const char *usbfs_path = NULL;
+/* clock ID for monotonic clock, as not all clock sources are available on all
+ * systems. appropriate choice made at initialization time. */
+static clockid_t monotonic_clkid = -1;
+
/* do we have a busnum to relate devices? this also implies that we can read
* the active configuration through bConfigurationValue */
static int sysfs_can_relate_devices = -1;
@@ -172,6 +176,38 @@ static const char *find_usbfs_path(void)
return ret;
}
+static clockid_t find_monotonic_clock(void)
+{
+ struct timespec ts;
+ int i;
+ const clockid_t clktypes[] = {
+ /* the most monotonic clock I know about, but only available since
+ * Linux 2.6.28, and not even available in glibc-2.10 */
+#ifndef CLOCK_MONOTONIC_RAW
+#define CLOCK_MONOTONIC_RAW 4
+#endif
+ CLOCK_MONOTONIC_RAW,
+
+ /* a monotonic clock, but it's not available on all architectures,
+ * and is susceptible to ntp adjustments */
+ CLOCK_MONOTONIC,
+
+ /* the fallback option */
+ CLOCK_REALTIME,
+ };
+
+ for (i = 0; i < (sizeof(clktypes) / sizeof(*clktypes)); i++) {
+ int r = clock_gettime(clktypes[i], &ts);
+ if (r == 0) {
+ usbi_dbg("clock %d selected", clktypes[i]);
+ return r;
+ }
+ usbi_dbg("clock %d doesn't work", clktypes[i]);
+ }
+
+ return -1;
+}
+
static int op_init(struct libusb_context *ctx)
{
struct stat statbuf;
@@ -183,6 +219,14 @@ static int op_init(struct libusb_context *ctx)
return LIBUSB_ERROR_OTHER;
}
+ if (monotonic_clkid == -1) {
+ monotonic_clkid = find_monotonic_clock();
+ if (monotonic_clkid == -1) {
+ usbi_err(ctx, "could not find working monotonic clock");
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+
r = stat(SYSFS_DEVICE_PATH, &statbuf);
if (r == 0 && S_ISDIR(statbuf.st_mode)) {
usbi_dbg("found usb devices in sysfs");
@@ -2036,7 +2080,7 @@ static int op_clock_gettime(int clk_id, struct timespec *tp)
{
switch (clk_id) {
case USBI_CLOCK_MONOTONIC:
- return clock_gettime(CLOCK_MONOTONIC, tp);
+ return clock_gettime(monotonic_clkid, tp);
case USBI_CLOCK_REALTIME:
return clock_gettime(CLOCK_REALTIME, tp);
default: