diff options
author | Daniel Drake <dsd@gentoo.org> | 2009-09-11 22:09:12 +0100 |
---|---|---|
committer | Daniel Drake <dsd@gentoo.org> | 2009-09-11 22:12:27 +0100 |
commit | 858684f0dd25921e09565034a88709dbf6f6c61b (patch) | |
tree | e45921eef51c4083197ba2cdc176e17f8d2f1cfa | |
parent | fe0d8dce1ed704915d501e7da700440c78144211 (diff) | |
download | libusb-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.c | 48 |
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: |