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#include "internal.h"
22
23uint64_t
24_dispatch_get_nanoseconds(void)
25{
26#if !TARGET_OS_WIN32
27	struct timeval now;
28	int r = gettimeofday(&now, NULL);
29	dispatch_assert_zero(r);
30	dispatch_assert(sizeof(NSEC_PER_SEC) == 8);
31	dispatch_assert(sizeof(NSEC_PER_USEC) == 8);
32	return (uint64_t)now.tv_sec * NSEC_PER_SEC +
33			(uint64_t)now.tv_usec * NSEC_PER_USEC;
34#else /* TARGET_OS_WIN32 */
35	// FILETIME is 100-nanosecond intervals since January 1, 1601 (UTC).
36	FILETIME ft;
37	ULARGE_INTEGER li;
38	GetSystemTimeAsFileTime(&ft);
39	li.LowPart = ft.dwLowDateTime;
40	li.HighPart = ft.dwHighDateTime;
41	return li.QuadPart * 100ull;
42#endif /* TARGET_OS_WIN32 */
43}
44
45#if !(defined(__i386__) || defined(__x86_64__) || !HAVE_MACH_ABSOLUTE_TIME) \
46		|| TARGET_OS_WIN32
47DISPATCH_CACHELINE_ALIGN _dispatch_host_time_data_s _dispatch_host_time_data;
48
49void
50_dispatch_get_host_time_init(void *context DISPATCH_UNUSED)
51{
52#if !TARGET_OS_WIN32
53	mach_timebase_info_data_t tbi;
54	(void)dispatch_assume_zero(mach_timebase_info(&tbi));
55	_dispatch_host_time_data.frac = tbi.numer;
56	_dispatch_host_time_data.frac /= tbi.denom;
57	_dispatch_host_time_data.ratio_1_to_1 = (tbi.numer == tbi.denom);
58#else
59	LARGE_INTEGER freq;
60	dispatch_assume(QueryPerformanceFrequency(&freq));
61	_dispatch_host_time_data.frac = (long double)NSEC_PER_SEC /
62			(long double)freq.QuadPart;
63	_dispatch_host_time_data.ratio_1_to_1 = (freq.QuadPart == 1);
64#endif	/* TARGET_OS_WIN32 */
65}
66#endif
67
68dispatch_time_t
69dispatch_time(dispatch_time_t inval, int64_t delta)
70{
71	uint64_t offset;
72	if (inval == DISPATCH_TIME_FOREVER) {
73		return DISPATCH_TIME_FOREVER;
74	}
75	if ((int64_t)inval < 0) {
76		// wall clock
77		if (delta >= 0) {
78			offset = (uint64_t)delta;
79			if ((int64_t)(inval -= offset) >= 0) {
80				return DISPATCH_TIME_FOREVER; // overflow
81			}
82			return inval;
83		} else {
84			offset = (uint64_t)-delta;
85			if ((int64_t)(inval += offset) >= -1) {
86				// -1 is special == DISPATCH_TIME_FOREVER == forever
87				return (dispatch_time_t)-2ll; // underflow
88			}
89			return inval;
90		}
91	}
92	// mach clock
93	if (inval == 0) {
94		inval = _dispatch_absolute_time();
95	}
96	if (delta >= 0) {
97		offset = _dispatch_time_nano2mach((uint64_t)delta);
98		if ((int64_t)(inval += offset) <= 0) {
99			return DISPATCH_TIME_FOREVER; // overflow
100		}
101		return inval;
102	} else {
103		offset = _dispatch_time_nano2mach((uint64_t)-delta);
104		if ((int64_t)(inval -= offset) < 1) {
105			return 1; // underflow
106		}
107		return inval;
108	}
109}
110
111dispatch_time_t
112dispatch_walltime(const struct timespec *inval, int64_t delta)
113{
114	int64_t nsec;
115	if (inval) {
116		nsec = inval->tv_sec * 1000000000ll + inval->tv_nsec;
117	} else {
118		nsec = (int64_t)_dispatch_get_nanoseconds();
119	}
120	nsec += delta;
121	if (nsec <= 1) {
122		// -1 is special == DISPATCH_TIME_FOREVER == forever
123		return delta >= 0 ? DISPATCH_TIME_FOREVER : (dispatch_time_t)-2ll;
124	}
125	return (dispatch_time_t)-nsec;
126}
127
128uint64_t
129_dispatch_timeout(dispatch_time_t when)
130{
131	dispatch_time_t now;
132	if (when == DISPATCH_TIME_FOREVER) {
133		return DISPATCH_TIME_FOREVER;
134	}
135	if (when == 0) {
136		return 0;
137	}
138	if ((int64_t)when < 0) {
139		when = (dispatch_time_t)-(int64_t)when;
140		now = _dispatch_get_nanoseconds();
141		return now >= when ? 0 : when - now;
142	}
143	now = _dispatch_absolute_time();
144	return now >= when ? 0 : _dispatch_time_mach2nano(when - now);
145}
146