2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <stdatomic.h>
33 #include <sys/types.h>
34 #include <sys/sysctl.h>
35 #include <mach/mach_error.h>
36 #include <mach/mach_time.h>
37 #include <os/base_private.h>
39 extern uint64_t __thread_selfusage(void);
41 #define timeval2nsec(tv) (tv.tv_sec * NSEC_PER_SEC + tv.tv_usec * NSEC_PER_USEC)
44 _boottime_fallback_usec(void)
47 size_t len
= sizeof(tv
);
48 int ret
= sysctlbyname("kern.boottime", &tv
, &len
, NULL
, 0);
49 if (ret
== -1) return 0;
50 return (uint64_t)tv
.tv_sec
* USEC_PER_SEC
+ (uint64_t)tv
.tv_usec
;
54 _mach_boottime_usec(uint64_t *boottime
, struct timeval
*realtime
)
56 uint64_t bt1
= 0, bt2
= 0;
59 bt1
= mach_boottime_usec();
60 if (os_slowpath(bt1
== 0)) bt1
= _boottime_fallback_usec();
62 atomic_thread_fence(memory_order_seq_cst
);
64 ret
= gettimeofday(realtime
, NULL
);
65 if (ret
!= 0) return ret
;
67 atomic_thread_fence(memory_order_seq_cst
);
69 bt2
= mach_boottime_usec();
70 if (os_slowpath(bt2
== 0)) bt2
= _boottime_fallback_usec();
71 } while (os_slowpath(bt1
!= bt2
));
77 clock_gettime_nsec_np(clockid_t clock_id
)
80 case CLOCK_REALTIME
: {
82 int ret
= gettimeofday(&tv
, NULL
);
84 return timeval2nsec(tv
);
86 case CLOCK_MONOTONIC
: {
89 int ret
= _mach_boottime_usec(&boottime
, &tv
);
91 boottime
*= NSEC_PER_USEC
;
92 return timeval2nsec(tv
) - boottime
;
94 case CLOCK_PROCESS_CPUTIME_ID
: {
96 int ret
= getrusage(RUSAGE_SELF
, &ru
);
98 return timeval2nsec(ru
.ru_utime
) + timeval2nsec(ru
.ru_stime
);
101 // calls that use mach_absolute_time units fall through into a common path
105 // Mach Absolute Time unit-based calls
106 mach_timebase_info_data_t tb_info
;
107 if (mach_timebase_info(&tb_info
)) return 0;
111 case CLOCK_MONOTONIC_RAW
:
112 mach_time
= mach_continuous_time();
114 case CLOCK_MONOTONIC_RAW_APPROX
:
115 mach_time
= mach_continuous_approximate_time();
117 case CLOCK_UPTIME_RAW
:
118 mach_time
= mach_absolute_time();
120 case CLOCK_UPTIME_RAW_APPROX
:
121 mach_time
= mach_approximate_time();
123 case CLOCK_THREAD_CPUTIME_ID
:
124 mach_time
= __thread_selfusage();
131 return (mach_time
* tb_info
.numer
) / tb_info
.denom
;
135 clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
138 case CLOCK_REALTIME
: {
140 int ret
= gettimeofday(&tv
, NULL
);
141 TIMEVAL_TO_TIMESPEC(&tv
, tp
);
144 case CLOCK_MONOTONIC
: {
146 uint64_t boottime_usec
;
147 int ret
= _mach_boottime_usec(&boottime_usec
, &tv
);
148 struct timeval boottime
= {
149 .tv_sec
= boottime_usec
/ USEC_PER_SEC
,
150 .tv_usec
= boottime_usec
% USEC_PER_SEC
152 timersub(&tv
, &boottime
, &tv
);
153 TIMEVAL_TO_TIMESPEC(&tv
, tp
);
156 case CLOCK_PROCESS_CPUTIME_ID
: {
158 int ret
= getrusage(RUSAGE_SELF
, &ru
);
159 timeradd(&ru
.ru_utime
, &ru
.ru_stime
, &ru
.ru_utime
);
160 TIMEVAL_TO_TIMESPEC(&ru
.ru_utime
, tp
);
163 case CLOCK_MONOTONIC_RAW
:
164 case CLOCK_MONOTONIC_RAW_APPROX
:
165 case CLOCK_UPTIME_RAW
:
166 case CLOCK_UPTIME_RAW_APPROX
:
167 case CLOCK_THREAD_CPUTIME_ID
: {
168 uint64_t ns
= clock_gettime_nsec_np(clk_id
);
171 tp
->tv_sec
= ns
/NSEC_PER_SEC
;
172 tp
->tv_nsec
= ns
% NSEC_PER_SEC
;
182 clock_getres(clockid_t clk_id
, struct timespec
*res
)
186 case CLOCK_MONOTONIC
:
187 case CLOCK_PROCESS_CPUTIME_ID
:
188 res
->tv_nsec
= NSEC_PER_USEC
;
192 case CLOCK_MONOTONIC_RAW
:
193 case CLOCK_MONOTONIC_RAW_APPROX
:
194 case CLOCK_UPTIME_RAW
:
195 case CLOCK_UPTIME_RAW_APPROX
:
196 case CLOCK_THREAD_CPUTIME_ID
: {
197 mach_timebase_info_data_t tb_info
;
198 if (mach_timebase_info(&tb_info
)){
201 res
->tv_nsec
= tb_info
.numer
/ tb_info
.denom
+ (tb_info
.numer
% tb_info
.denom
!= 0);
213 clock_settime(clockid_t clk_id
, const struct timespec
*tp
)
216 case CLOCK_REALTIME
: {
218 TIMESPEC_TO_TIMEVAL(&tv
,tp
)
219 return settimeofday(&tv
, NULL
);