diff --git a/configure.ac b/configure.ac index ef9c370..384939f 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,10 @@ AC_TYPE_UINT32_T AC_CHECK_TYPE([struct timespec], [], [AC_MSG_ERROR([missing struct timespec])], [[#include ]]) # Checks for functions. -AC_CHECK_FUNCS([clock_gettime], [], [AC_MSG_ERROR([missing clock_gettime])]) +AC_CHECK_FUNCS([clock_gettime], + [AC_DEFINE([HAVE_CLOCK_GETTIME])], + [AC_CHECK_FUNCS([host_get_clock_service], [AC_DEFINE([HAVE_HOST_GET_CLOCK_SERVICE])], [AC_MSG_ERROR([no clock_gettime or host_get_clock_service])])] +) # Checks for compiler flags. CCHECKFLAGS="-Wno-error" diff --git a/libcurvecpr/lib/util.c b/libcurvecpr/lib/util.c index 16ba18b..08fc8cc 100644 --- a/libcurvecpr/lib/util.c +++ b/libcurvecpr/lib/util.c @@ -5,6 +5,13 @@ #include #include +#ifdef HAVE_HOST_GET_CLOCK_SERVICE +#include +#include +#include +#include +#include +#endif #include @@ -29,9 +36,37 @@ long long curvecpr_util_random_mod_n (long long n) /* XXX: Nanosecond granularity limits users to 1 terabyte per second. */ long long curvecpr_util_nanoseconds (void) { + /* XXX: host_get_clock_service() has been officially deprecated for years; + this may need to be updated in the future. */ +#ifdef HAVE_HOST_GET_CLOCK_SERVICE + static int32_t cclock_registered = 0; + static volatile clock_serv_t cclock = 0; + mach_timespec_t t; + + if (!cclock) { + if (OSAtomicCompareAndSwap32Barrier(0, 1, &cclock_registered) == 1) { + clock_serv_t cclock_actual; + + if (host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock_actual) != KERN_SUCCESS) { + cclock_registered = 0; + return -1; + } + + cclock = cclock_actual; + } else { + while (!cclock) + /* Wait for clock to become available */; + } + } + + if (clock_get_time(cclock, &t) != KERN_SUCCESS) + return -1; +#else struct timespec t; + if (clock_gettime(CLOCK_REALTIME, &t) != 0) return -1; +#endif return t.tv_sec * 1000000000LL + t.tv_nsec; } diff --git a/libcurvecpr/test/Makefile.am b/libcurvecpr/test/Makefile.am index e64c47f..03ce746 100644 --- a/libcurvecpr/test/Makefile.am +++ b/libcurvecpr/test/Makefile.am @@ -13,4 +13,7 @@ messager_test_recv_requests_removal_from_sendmarkq_SOURCES = messager/test_recv_ check_PROGRAMS += messager/test_send_with_1_failure_moves_message_from_sendq messager_test_send_with_1_failure_moves_message_from_sendq_SOURCES = messager/test_send_with_1_failure_moves_message_from_sendq.c +check_PROGRAMS += util/test_nanoseconds +util_test_nanoseconds_SOURCES = util/test_nanoseconds.c + TESTS = $(check_PROGRAMS) diff --git a/libcurvecpr/test/util/test_nanoseconds.c b/libcurvecpr/test/util/test_nanoseconds.c new file mode 100644 index 0000000..28fc414 --- /dev/null +++ b/libcurvecpr/test/util/test_nanoseconds.c @@ -0,0 +1,22 @@ +#include +#include + +#include + +START_TEST (test_nanoseconds) +{ + long long nanoseconds = curvecpr_util_nanoseconds(); + + fail_if(nanoseconds < 0); + fail_unless(nanoseconds > 1374047000000000000LL); + + /* On OS X, we may cache the kernel clock reference. Make sure it still + works. */ + nanoseconds = curvecpr_util_nanoseconds(); + + fail_if(nanoseconds < 0); + fail_unless(nanoseconds > 1374047000000000000LL); +} +END_TEST + +RUN_TEST (test_nanoseconds)