/* * Copyright (c) 2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include <stdbool.h> #include <sys/types.h> #include <sys/time.h> #include <mach/mach_time.h> #include <sys/time.h> #include <machine/cpu_capabilities.h> // From __commpage_gettimeofday.c extern int __commpage_gettimeofday_internal(struct timeval *tp, uint64_t *tbr_out); extern kern_return_t _mach_continuous_time(uint64_t* absolute_time, uint64_t* cont_time); // From mach_continuous_time.c extern uint64_t _mach_continuous_time_base(void); // Underlying syscall stub extern int __gettimeofday_with_mach(struct timeval *, struct timezone *, uint64_t *); kern_return_t mach_get_times(uint64_t* absolute_time, uint64_t* cont_time, struct timespec *tp) { if (tp == NULL) { return _mach_continuous_time(absolute_time, cont_time); } uint64_t continuous_time_base_prior = -1, continuous_time_base_post = -1; uint64_t tbr; struct timeval tv; do { /* * We need to capture the result of gettimeofday without our continuous * time base changing. Once we have that, and the value for absolute * time that was used to compute the timespec, we can just add the base * to get the accompanying continuous time. */ continuous_time_base_prior = _mach_continuous_time_base(); /* * This call has the necessary memory barriers for this retry loop, * since it is implemented with a retry loop of its own. */ if (__commpage_gettimeofday_internal(&tv, &tbr)) { tbr = 0; if (__gettimeofday_with_mach(&tv, NULL, &tbr) < 0) { return KERN_FAILURE; } else if (tbr == 0) { #if !TARGET_OS_EMBEDDED // On an old kernel, likely chroot'ed. (remove next year) tbr = mach_absolute_time(); #else __builtin_trap(); #endif } } continuous_time_base_post = _mach_continuous_time_base(); } while (__builtin_expect(continuous_time_base_prior != continuous_time_base_post, 0)); if (absolute_time) *absolute_time = tbr; if (cont_time) *cont_time = continuous_time_base_prior + tbr; tp->tv_sec = tv.tv_sec; tp->tv_nsec = tv.tv_usec * NSEC_PER_USEC; return KERN_SUCCESS; }