Skip to content

Commit

Permalink
Updated OS X support code.
Browse files Browse the repository at this point in the history
* Fixed warnings in existing implementation.
* Cached port returned by host_get_clock_service().
* Added unit test for curvecpr_util_nanoseconds().

Refs #4.
  • Loading branch information
impl committed Jul 17, 2013
1 parent 43c9dc8 commit b31616c
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 17 deletions.
9 changes: 4 additions & 5 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ AC_TYPE_UINT32_T
AC_CHECK_TYPE([struct timespec], [], [AC_MSG_ERROR([missing struct timespec])], [[#include <time.h>]])

# Checks for functions.
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])])
])
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"
Expand Down
44 changes: 32 additions & 12 deletions libcurvecpr/lib/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
#include <curvecpr/bytes.h>

#include <time.h>

#include <sodium/randombytes.h>

#ifdef HAVE_HOST_GET_CLOCK_SERVICE
#include <libkern/OSAtomic.h>
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <stdint.h>
#endif

#include <sodium/randombytes.h>

/* XXX: Current implementation is limited to n < 2^55. */
long long curvecpr_util_random_mod_n (long long n)
{
Expand All @@ -34,18 +36,36 @@ 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)
{
#if defined(HAVE_CLOCK_GETTIME)
/* 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;
#elif defined(HAVE_HOST_GET_CLOCK_SERVICE)
clock_serv_t clock;
mach_timespec_t t;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock);
clock_get_time(clock, &t);
mach_port_deallocate(mach_task_self(), clock);
#else
#error "no function for getting microseconds"
#endif

return t.tv_sec * 1000000000LL + t.tv_nsec;
Expand Down
3 changes: 3 additions & 0 deletions libcurvecpr/test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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)
22 changes: 22 additions & 0 deletions libcurvecpr/test/util/test_nanoseconds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <check.h>
#include <check_extras.h>

#include <curvecpr/util.h>

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)

0 comments on commit b31616c

Please sign in to comment.