summaryrefslogtreecommitdiff
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
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.
-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: