55#include <curvecpr/bytes.h>
66
77#include <time.h>
8-
9- #include <sodium/randombytes.h>
10-
118#ifdef HAVE_HOST_GET_CLOCK_SERVICE
9+ #include <libkern/OSAtomic.h>
1210#include <mach/clock.h>
1311#include <mach/mach.h>
12+ #include <mach/mach_error.h>
13+ #include <stdint.h>
1414#endif
1515
16+ #include <sodium/randombytes.h>
17+
1618/* XXX: Current implementation is limited to n < 2^55. */
1719long long curvecpr_util_random_mod_n (long long n )
1820{
@@ -34,18 +36,36 @@ long long curvecpr_util_random_mod_n (long long n)
3436/* XXX: Nanosecond granularity limits users to 1 terabyte per second. */
3537long long curvecpr_util_nanoseconds (void )
3638{
37- #if defined(HAVE_CLOCK_GETTIME )
39+ /* XXX: host_get_clock_service() has been officially deprecated for years;
40+ this may need to be updated in the future. */
41+ #ifdef HAVE_HOST_GET_CLOCK_SERVICE
42+ static int32_t cclock_registered = 0 ;
43+ static volatile clock_serv_t cclock = 0 ;
44+ mach_timespec_t t ;
45+
46+ if (!cclock ) {
47+ if (OSAtomicCompareAndSwap32Barrier (0 , 1 , & cclock_registered ) == 1 ) {
48+ clock_serv_t cclock_actual ;
49+
50+ if (host_get_clock_service (mach_host_self (), CALENDAR_CLOCK , & cclock_actual ) != KERN_SUCCESS ) {
51+ cclock_registered = 0 ;
52+ return -1 ;
53+ }
54+
55+ cclock = cclock_actual ;
56+ } else {
57+ while (!cclock )
58+ /* Wait for clock to become available */ ;
59+ }
60+ }
61+
62+ if (clock_get_time (cclock , & t ) != KERN_SUCCESS )
63+ return -1 ;
64+ #else
3865 struct timespec t ;
66+
3967 if (clock_gettime (CLOCK_REALTIME , & t ) != 0 )
4068 return -1 ;
41- #elif defined(HAVE_HOST_GET_CLOCK_SERVICE )
42- clock_serv_t clock ;
43- mach_timespec_t t ;
44- host_get_clock_service (mach_host_self (), CALENDAR_CLOCK , & clock );
45- clock_get_time (clock , & t );
46- mach_port_deallocate (mach_task_self (), clock );
47- #else
48- #error "no function for getting microseconds"
4969#endif
5070
5171 return t .tv_sec * 1000000000LL + t .tv_nsec ;
0 commit comments