xref: /xnu-10002.81.5/libsyscall/wrappers/mach_get_times.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1 /*
2  * Copyright (c) 2015 Apple Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. Please obtain a copy of the License at
10  * http://www.opensource.apple.com/apsl/ and read it before using this
11  * file.
12  *
13  * The Original Code and all software distributed under the License are
14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18  * Please see the License for the specific language governing rights and
19  * limitations under the License.
20  *
21  * @APPLE_LICENSE_HEADER_END@
22  */
23 #include <stdbool.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <mach/mach_time.h>
27 #include <sys/time.h>
28 #include <machine/cpu_capabilities.h>
29 
30 // From __commpage_gettimeofday.c
31 extern int __commpage_gettimeofday_internal(struct timeval *tp, uint64_t *tbr_out);
32 extern kern_return_t _mach_continuous_time(uint64_t* absolute_time, uint64_t* cont_time);
33 // From mach_continuous_time.c
34 extern uint64_t _mach_continuous_time_base(void);
35 // Underlying syscall stub
36 extern int __gettimeofday_with_mach(struct timeval *, struct timezone *, uint64_t *);
37 
38 kern_return_t
mach_get_times(uint64_t * absolute_time,uint64_t * cont_time,struct timespec * tp)39 mach_get_times(uint64_t* absolute_time, uint64_t* cont_time, struct timespec *tp)
40 {
41 	if (tp == NULL) {
42 		return _mach_continuous_time(absolute_time, cont_time);
43 	}
44 
45 	uint64_t continuous_time_base_prior = -1, continuous_time_base_post = -1;
46 	uint64_t tbr;
47 	struct timeval tv;
48 
49 	do {
50 		/*
51 		 * We need to capture the result of gettimeofday without our continuous
52 		 * time base changing.  Once we have that, and the value for absolute
53 		 * time that was used to compute the timespec, we can just add the base
54 		 * to get the accompanying continuous time.
55 		 */
56 		continuous_time_base_prior = _mach_continuous_time_base();
57 
58 		/*
59 		 * This call has the necessary memory barriers for this retry loop,
60 		 * since it is implemented with a retry loop of its own.
61 		 */
62 		if (__commpage_gettimeofday_internal(&tv, &tbr)) {
63 			tbr = 0;
64 			if (__gettimeofday_with_mach(&tv, NULL, &tbr) < 0) {
65 				return KERN_FAILURE;
66 			} else if (tbr == 0) {
67 				__builtin_trap();
68 			}
69 		}
70 
71 		continuous_time_base_post = _mach_continuous_time_base();
72 	} while (__builtin_expect(continuous_time_base_prior != continuous_time_base_post, 0));
73 
74 	if (absolute_time) {
75 		*absolute_time = tbr;
76 	}
77 	if (cont_time) {
78 		*cont_time = continuous_time_base_prior + tbr;
79 	}
80 	tp->tv_sec = tv.tv_sec;
81 	tp->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
82 
83 	return KERN_SUCCESS;
84 }
85