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
34DISPATCH_ALWAYS_INLINE_NDEBUG
35static inline void
36_dispatch_contention_usleep(unsigned int us)
37{
38#if HAVE_MACH
39#if defined(SWITCH_OPTION_DISPATCH_CONTENTION) && !(TARGET_IPHONE_SIMULATOR && \
40		IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED < 1090)
41	thread_switch(MACH_PORT_NULL, SWITCH_OPTION_DISPATCH_CONTENTION, us);
42#else
43	thread_switch(MACH_PORT_NULL, SWITCH_OPTION_WAIT, ((us-1)/1000)+1);
44#endif
45#else
46	usleep(us);
47#endif
48}
49
50#if TARGET_OS_WIN32
51static inline unsigned int
52sleep(unsigned int seconds)
53{
54	Sleep(seconds * 1000); // milliseconds
55	return 0;
56}
57#endif
58
59uint64_t _dispatch_get_nanoseconds(void);
60
61#if defined(__i386__) || defined(__x86_64__) || !HAVE_MACH_ABSOLUTE_TIME
62// x86 currently implements mach time in nanoseconds
63// this is NOT likely to change
64DISPATCH_ALWAYS_INLINE
65static inline uint64_t
66_dispatch_time_mach2nano(uint64_t machtime)
67{
68	return machtime;
69}
70
71DISPATCH_ALWAYS_INLINE
72static inline uint64_t
73_dispatch_time_nano2mach(uint64_t nsec)
74{
75	return nsec;
76}
77#else
78typedef struct _dispatch_host_time_data_s {
79	dispatch_once_t pred;
80	long double frac;
81	bool ratio_1_to_1;
82} _dispatch_host_time_data_s;
83extern _dispatch_host_time_data_s _dispatch_host_time_data;
84void _dispatch_get_host_time_init(void *context);
85
86static inline uint64_t
87_dispatch_time_mach2nano(uint64_t machtime)
88{
89	_dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
90	dispatch_once_f(&data->pred, NULL, _dispatch_get_host_time_init);
91
92	if (!machtime || slowpath(data->ratio_1_to_1)) {
93		return machtime;
94	}
95	if (machtime >= INT64_MAX) {
96		return INT64_MAX;
97	}
98	long double big_tmp = ((long double)machtime * data->frac) + .5;
99	if (slowpath(big_tmp >= INT64_MAX)) {
100		return INT64_MAX;
101	}
102	return (uint64_t)big_tmp;
103}
104
105static inline uint64_t
106_dispatch_time_nano2mach(uint64_t nsec)
107{
108	_dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
109	dispatch_once_f(&data->pred, NULL, _dispatch_get_host_time_init);
110
111	if (!nsec || slowpath(data->ratio_1_to_1)) {
112		return nsec;
113	}
114	if (nsec >= INT64_MAX) {
115		return INT64_MAX;
116	}
117	long double big_tmp = ((long double)nsec / data->frac) + .5;
118	if (slowpath(big_tmp >= INT64_MAX)) {
119		return INT64_MAX;
120	}
121	return (uint64_t)big_tmp;
122}
123#endif
124
125static inline uint64_t
126_dispatch_absolute_time(void)
127{
128#if HAVE_MACH_ABSOLUTE_TIME
129	return mach_absolute_time();
130#elif TARGET_OS_WIN32
131	LARGE_INTEGER now;
132	return QueryPerformanceCounter(&now) ? now.QuadPart : 0;
133#else
134	struct timespec ts;
135	int ret;
136
137#if HAVE_DECL_CLOCK_UPTIME
138	ret = clock_gettime(CLOCK_UPTIME, &ts);
139#elif HAVE_DECL_CLOCK_MONOTONIC
140	ret = clock_gettime(CLOCK_MONOTONIC, &ts);
141#else
142#error "clock_gettime: no supported absolute time clock"
143#endif
144	(void)dispatch_assume_zero(ret);
145
146	/* XXXRW: Some kind of overflow detection needed? */
147	return (ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec);
148#endif // HAVE_MACH_ABSOLUTE_TIME
149}
150
151
152#endif // __DISPATCH_SHIMS_TIME__
153