]> git.saurik.com Git - apple/libdispatch.git/blob - src/shims/time.h
libdispatch-703.50.37.tar.gz
[apple/libdispatch.git] / src / shims / time.h
1 /*
2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 /*
22 * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
23 * which are subject to change in future releases of Mac OS X. Any applications
24 * relying on these interfaces WILL break.
25 */
26
27 #ifndef __DISPATCH_SHIMS_TIME__
28 #define __DISPATCH_SHIMS_TIME__
29
30 #ifndef __DISPATCH_INDIRECT__
31 #error "Please #include <dispatch/dispatch.h> instead of this file directly."
32 #endif
33
34 #if TARGET_OS_WIN32
35 static inline unsigned int
36 sleep(unsigned int seconds)
37 {
38 Sleep(seconds * 1000); // milliseconds
39 return 0;
40 }
41 #endif
42
43 typedef enum {
44 DISPATCH_CLOCK_WALL,
45 DISPATCH_CLOCK_MACH,
46 #define DISPATCH_CLOCK_COUNT (DISPATCH_CLOCK_MACH + 1)
47 } dispatch_clock_t;
48
49 #if defined(__i386__) || defined(__x86_64__) || !HAVE_MACH_ABSOLUTE_TIME
50 // x86 currently implements mach time in nanoseconds
51 // this is NOT likely to change
52 DISPATCH_ALWAYS_INLINE
53 static inline uint64_t
54 _dispatch_time_mach2nano(uint64_t machtime)
55 {
56 return machtime;
57 }
58
59 DISPATCH_ALWAYS_INLINE
60 static inline uint64_t
61 _dispatch_time_nano2mach(uint64_t nsec)
62 {
63 return nsec;
64 }
65 #else
66 typedef struct _dispatch_host_time_data_s {
67 dispatch_once_t pred;
68 long double frac;
69 bool ratio_1_to_1;
70 } _dispatch_host_time_data_s;
71 extern _dispatch_host_time_data_s _dispatch_host_time_data;
72 void _dispatch_get_host_time_init(void *context);
73
74 static inline uint64_t
75 _dispatch_time_mach2nano(uint64_t machtime)
76 {
77 _dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
78 dispatch_once_f(&data->pred, NULL, _dispatch_get_host_time_init);
79
80 if (!machtime || slowpath(data->ratio_1_to_1)) {
81 return machtime;
82 }
83 if (machtime >= INT64_MAX) {
84 return INT64_MAX;
85 }
86 long double big_tmp = ((long double)machtime * data->frac) + .5;
87 if (slowpath(big_tmp >= INT64_MAX)) {
88 return INT64_MAX;
89 }
90 return (uint64_t)big_tmp;
91 }
92
93 static inline uint64_t
94 _dispatch_time_nano2mach(uint64_t nsec)
95 {
96 _dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
97 dispatch_once_f(&data->pred, NULL, _dispatch_get_host_time_init);
98
99 if (!nsec || slowpath(data->ratio_1_to_1)) {
100 return nsec;
101 }
102 if (nsec >= INT64_MAX) {
103 return INT64_MAX;
104 }
105 long double big_tmp = ((long double)nsec / data->frac) + .5;
106 if (slowpath(big_tmp >= INT64_MAX)) {
107 return INT64_MAX;
108 }
109 return (uint64_t)big_tmp;
110 }
111 #endif
112
113 /* XXXRW: Some kind of overflow detection needed? */
114 #define _dispatch_timespec_to_nano(ts) \
115 ((uint64_t)(ts).tv_sec * NSEC_PER_SEC + (uint64_t)(ts).tv_nsec)
116 #define _dispatch_timeval_to_nano(tv) \
117 ((uint64_t)(tv).tv_sec * NSEC_PER_SEC + \
118 (uint64_t)(tv).tv_usec * NSEC_PER_USEC)
119
120 static inline uint64_t
121 _dispatch_get_nanoseconds(void)
122 {
123 dispatch_static_assert(sizeof(NSEC_PER_SEC) == 8);
124 dispatch_static_assert(sizeof(USEC_PER_SEC) == 8);
125
126 #if TARGET_OS_MAC && DISPATCH_HOST_SUPPORTS_OSX(101200)
127 return clock_gettime_nsec_np(CLOCK_REALTIME);
128 #elif HAVE_DECL_CLOCK_REALTIME
129 struct timespec ts;
130 dispatch_assume_zero(clock_gettime(CLOCK_REALTIME, &ts));
131 return _dispatch_timespec_to_nano(ts);
132 #elif TARGET_OS_WIN32
133 // FILETIME is 100-nanosecond intervals since January 1, 1601 (UTC).
134 FILETIME ft;
135 ULARGE_INTEGER li;
136 GetSystemTimeAsFileTime(&ft);
137 li.LowPart = ft.dwLowDateTime;
138 li.HighPart = ft.dwHighDateTime;
139 return li.QuadPart * 100ull;
140 #else
141 struct timeval tv;
142 dispatch_assert_zero(gettimeofday(&tv, NULL));
143 return _dispatch_timeval_to_nano(tv);
144 #endif
145 }
146
147 static inline uint64_t
148 _dispatch_absolute_time(void)
149 {
150 #if HAVE_MACH_ABSOLUTE_TIME
151 return mach_absolute_time();
152 #elif HAVE_DECL_CLOCK_UPTIME && !defined(__linux__)
153 struct timespec ts;
154 dispatch_assume_zero(clock_gettime(CLOCK_UPTIME, &ts));
155 return _dispatch_timespec_to_nano(ts);
156 #elif HAVE_DECL_CLOCK_MONOTONIC
157 struct timespec ts;
158 dispatch_assume_zero(clock_gettime(CLOCK_MONOTONIC, &ts));
159 return _dispatch_timespec_to_nano(ts);
160 #elif TARGET_OS_WIN32
161 LARGE_INTEGER now;
162 return QueryPerformanceCounter(&now) ? now.QuadPart : 0;
163 #else
164 #error platform needs to implement _dispatch_absolute_time()
165 #endif
166 }
167
168 DISPATCH_ALWAYS_INLINE
169 static inline uint64_t
170 _dispatch_approximate_time(void)
171 {
172 return _dispatch_absolute_time();
173 }
174
175 DISPATCH_ALWAYS_INLINE
176 static inline uint64_t
177 _dispatch_time_now(dispatch_clock_t clock)
178 {
179 switch (clock) {
180 case DISPATCH_CLOCK_MACH:
181 return _dispatch_absolute_time();
182 case DISPATCH_CLOCK_WALL:
183 return _dispatch_get_nanoseconds();
184 }
185 __builtin_unreachable();
186 }
187
188 typedef struct {
189 uint64_t nows[DISPATCH_CLOCK_COUNT];
190 } dispatch_clock_now_cache_s, *dispatch_clock_now_cache_t;
191
192 DISPATCH_ALWAYS_INLINE
193 static inline uint64_t
194 _dispatch_time_now_cached(dispatch_clock_t clock,
195 dispatch_clock_now_cache_t cache)
196 {
197 if (likely(cache->nows[clock])) {
198 return cache->nows[clock];
199 }
200 return cache->nows[clock] = _dispatch_time_now(clock);
201 }
202
203 #endif // __DISPATCH_SHIMS_TIME__