]> git.saurik.com Git - apple/libdispatch.git/blob - src/time.c
libdispatch-84.5.tar.gz
[apple/libdispatch.git] / src / time.c
1 /*
2 * Copyright (c) 2008-2009 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
23 uint64_t
24 _dispatch_get_nanoseconds(void)
25 {
26 struct timeval now;
27 int r = gettimeofday(&now, NULL);
28 dispatch_assert_zero(r);
29 dispatch_assert(sizeof(NSEC_PER_SEC) == 8);
30 dispatch_assert(sizeof(NSEC_PER_USEC) == 8);
31 return now.tv_sec * NSEC_PER_SEC + now.tv_usec * NSEC_PER_USEC;
32 }
33
34 #if defined(__i386__) || defined(__x86_64__)
35 // x86 currently implements mach time in nanoseconds; this is NOT likely to change
36 #define _dispatch_time_mach2nano(x) (x)
37 #define _dispatch_time_nano2mach(x) (x)
38 #else
39 static struct _dispatch_host_time_data_s {
40 mach_timebase_info_data_t tbi;
41 uint64_t safe_numer_math;
42 dispatch_once_t pred;
43 } _dispatch_host_time_data;
44
45 static void
46 _dispatch_get_host_time_init(void *context __attribute__((unused)))
47 {
48 dispatch_assume_zero(mach_timebase_info(&_dispatch_host_time_data.tbi));
49 _dispatch_host_time_data.safe_numer_math = DISPATCH_TIME_FOREVER / _dispatch_host_time_data.tbi.numer;
50 }
51
52 static uint64_t
53 _dispatch_time_mach2nano(uint64_t nsec)
54 {
55 struct _dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
56 uint64_t small_tmp = nsec;
57 #ifdef __LP64__
58 __uint128_t big_tmp = nsec;
59 #else
60 long double big_tmp = nsec;
61 #endif
62
63 dispatch_once_f(&data->pred, NULL, _dispatch_get_host_time_init);
64
65 if (slowpath(data->tbi.numer != data->tbi.denom)) {
66 if (nsec < data->safe_numer_math) {
67 small_tmp *= data->tbi.numer;
68 small_tmp /= data->tbi.denom;
69 } else {
70 big_tmp *= data->tbi.numer;
71 big_tmp /= data->tbi.denom;
72 small_tmp = big_tmp;
73 }
74 }
75 return small_tmp;
76 }
77
78 static int64_t
79 _dispatch_time_nano2mach(int64_t nsec)
80 {
81 struct _dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
82 #ifdef __LP64__
83 __int128_t big_tmp = nsec;
84 #else
85 long double big_tmp = nsec;
86 #endif
87
88 dispatch_once_f(&data->pred, NULL, _dispatch_get_host_time_init);
89
90 if (fastpath(data->tbi.numer == data->tbi.denom)) {
91 return nsec;
92 }
93
94 // Multiply by the inverse to convert nsec to Mach absolute time
95 big_tmp *= data->tbi.denom;
96 big_tmp /= data->tbi.numer;
97
98 if (big_tmp > INT64_MAX) {
99 return INT64_MAX;
100 }
101 if (big_tmp < INT64_MIN) {
102 return INT64_MIN;
103 }
104 return big_tmp;
105 }
106 #endif
107
108 dispatch_time_t
109 dispatch_time(dispatch_time_t inval, int64_t delta)
110 {
111 if (inval == DISPATCH_TIME_FOREVER) {
112 return DISPATCH_TIME_FOREVER;
113 }
114 if ((int64_t)inval < 0) {
115 // wall clock
116 if (delta >= 0) {
117 if ((int64_t)(inval -= delta) >= 0) {
118 return DISPATCH_TIME_FOREVER; // overflow
119 }
120 return inval;
121 }
122 if ((int64_t)(inval -= delta) >= -1) {
123 // -1 is special == DISPATCH_TIME_FOREVER == forever
124 return -2; // underflow
125 }
126 return inval;
127 }
128 // mach clock
129 delta = _dispatch_time_nano2mach(delta);
130 if (inval == 0) {
131 inval = mach_absolute_time();
132 }
133 if (delta >= 0) {
134 if ((int64_t)(inval += delta) <= 0) {
135 return DISPATCH_TIME_FOREVER; // overflow
136 }
137 return inval;
138 }
139 if ((int64_t)(inval += delta) < 1) {
140 return 1; // underflow
141 }
142 return inval;
143 }
144
145 dispatch_time_t
146 dispatch_walltime(const struct timespec *inval, int64_t delta)
147 {
148 int64_t nsec;
149
150 if (inval) {
151 nsec = inval->tv_sec * 1000000000ull + inval->tv_nsec;
152 } else {
153 nsec = _dispatch_get_nanoseconds();
154 }
155
156 nsec += delta;
157 if (nsec <= 1) {
158 // -1 is special == DISPATCH_TIME_FOREVER == forever
159 return delta >= 0 ? DISPATCH_TIME_FOREVER : (uint64_t)-2ll;
160 }
161
162 return -nsec;
163 }
164
165 uint64_t
166 _dispatch_timeout(dispatch_time_t when)
167 {
168 uint64_t now;
169
170 if (when == DISPATCH_TIME_FOREVER) {
171 return DISPATCH_TIME_FOREVER;
172 }
173 if (when == 0) {
174 return 0;
175 }
176 if ((int64_t)when < 0) {
177 when = -(int64_t)when;
178 now = _dispatch_get_nanoseconds();
179 return now >= when ? 0 : when - now;
180 }
181 now = mach_absolute_time();
182 return now >= when ? 0 : _dispatch_time_mach2nano(when - now);
183 }