/* * 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 #include #include #include #include __attribute__((visibility("hidden"))) uint64_t _mach_continuous_time_base(void) { #if !defined(__x86_64__) && !defined(__arm64__) // Deal with the lack of 64-bit loads on arm32 (see mach_approximate_time.s) while(1) { volatile uint64_t *base_ptr = (volatile uint64_t*)_COMM_PAGE_CONT_TIMEBASE; uint64_t read1, read2; read1 = *base_ptr; #if defined(__i386__) __asm__ volatile("lfence" ::: "memory"); #else #error "unsupported arch" #endif read2 = *base_ptr; if(__builtin_expect((read1 == read2), 1)) return read1; } #else // 64-bit return *(volatile uint64_t*)_COMM_PAGE_CONT_TIMEBASE; #endif // 64-bit } __attribute__((visibility("hidden"))) kern_return_t _mach_continuous_time(uint64_t* absolute_time, uint64_t* cont_time) { volatile uint64_t *base_ptr = (volatile uint64_t*)_COMM_PAGE_CONT_TIMEBASE; volatile uint64_t read1, read2; volatile uint64_t absolute; do { read1 = *base_ptr; absolute = mach_absolute_time(); read2 = *base_ptr; } while (__builtin_expect((read1 != read2), 0)); if (absolute_time) *absolute_time = absolute; if (cont_time) *cont_time = absolute + read1; return KERN_SUCCESS; } uint64_t mach_continuous_time(void) { uint64_t cont_time; _mach_continuous_time(NULL, &cont_time); return cont_time; } uint64_t mach_continuous_approximate_time(void) { /* * No retry loop here because if we use a slightly too old timebase that's * okay, we are approximate time anyway. */ volatile register uint64_t time_base = _mach_continuous_time_base(); return time_base + mach_approximate_time(); }