]> git.saurik.com Git - apple/libdispatch.git/blob - src/time.c
libdispatch-913.1.6.tar.gz
[apple/libdispatch.git] / src / time.c
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
23 #if DISPATCH_USE_HOST_TIME
24 typedef struct _dispatch_host_time_data_s {
25 long double frac;
26 bool ratio_1_to_1;
27 } _dispatch_host_time_data_s;
28
29 DISPATCH_CACHELINE_ALIGN
30 static _dispatch_host_time_data_s _dispatch_host_time_data;
31
32 uint64_t (*_dispatch_host_time_mach2nano)(uint64_t machtime);
33 uint64_t (*_dispatch_host_time_nano2mach)(uint64_t nsec);
34
35 static uint64_t
36 _dispatch_mach_host_time_mach2nano(uint64_t machtime)
37 {
38 _dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
39
40 if (unlikely(!machtime || data->ratio_1_to_1)) {
41 return machtime;
42 }
43 if (machtime >= INT64_MAX) {
44 return INT64_MAX;
45 }
46 long double big_tmp = ((long double)machtime * data->frac) + .5L;
47 if (unlikely(big_tmp >= INT64_MAX)) {
48 return INT64_MAX;
49 }
50 return (uint64_t)big_tmp;
51 }
52
53 static uint64_t
54 _dispatch_mach_host_time_nano2mach(uint64_t nsec)
55 {
56 _dispatch_host_time_data_s *const data = &_dispatch_host_time_data;
57
58 if (unlikely(!nsec || data->ratio_1_to_1)) {
59 return nsec;
60 }
61 if (nsec >= INT64_MAX) {
62 return INT64_MAX;
63 }
64 long double big_tmp = ((long double)nsec / data->frac) + .5L;
65 if (unlikely(big_tmp >= INT64_MAX)) {
66 return INT64_MAX;
67 }
68 return (uint64_t)big_tmp;
69 }
70
71 static void
72 _dispatch_host_time_init(mach_timebase_info_data_t *tbi)
73 {
74 _dispatch_host_time_data.frac = tbi->numer;
75 _dispatch_host_time_data.frac /= tbi->denom;
76 _dispatch_host_time_data.ratio_1_to_1 = (tbi->numer == tbi->denom);
77 _dispatch_host_time_mach2nano = _dispatch_mach_host_time_mach2nano;
78 _dispatch_host_time_nano2mach = _dispatch_mach_host_time_nano2mach;
79 }
80 #endif // DISPATCH_USE_HOST_TIME
81
82 void
83 _dispatch_time_init(void)
84 {
85 #if DISPATCH_USE_HOST_TIME
86 mach_timebase_info_data_t tbi;
87 (void)dispatch_assume_zero(mach_timebase_info(&tbi));
88 _dispatch_host_time_init(&tbi);
89 #endif // DISPATCH_USE_HOST_TIME
90 }
91
92 dispatch_time_t
93 dispatch_time(dispatch_time_t inval, int64_t delta)
94 {
95 uint64_t offset;
96 if (inval == DISPATCH_TIME_FOREVER) {
97 return DISPATCH_TIME_FOREVER;
98 }
99 if ((int64_t)inval < 0) {
100 // wall clock
101 if (delta >= 0) {
102 offset = (uint64_t)delta;
103 if ((int64_t)(inval -= offset) >= 0) {
104 return DISPATCH_TIME_FOREVER; // overflow
105 }
106 return inval;
107 } else {
108 offset = (uint64_t)-delta;
109 if ((int64_t)(inval += offset) >= -1) {
110 // -1 is special == DISPATCH_TIME_FOREVER == forever
111 return (dispatch_time_t)-2ll; // underflow
112 }
113 return inval;
114 }
115 }
116 // mach clock
117 if (inval == 0) {
118 inval = _dispatch_absolute_time();
119 }
120 if (delta >= 0) {
121 offset = _dispatch_time_nano2mach((uint64_t)delta);
122 if ((int64_t)(inval += offset) <= 0) {
123 return DISPATCH_TIME_FOREVER; // overflow
124 }
125 return inval;
126 } else {
127 offset = _dispatch_time_nano2mach((uint64_t)-delta);
128 if ((int64_t)(inval -= offset) < 1) {
129 return 1; // underflow
130 }
131 return inval;
132 }
133 }
134
135 dispatch_time_t
136 dispatch_walltime(const struct timespec *inval, int64_t delta)
137 {
138 int64_t nsec;
139 if (inval) {
140 nsec = (int64_t)_dispatch_timespec_to_nano(*inval);
141 } else {
142 nsec = (int64_t)_dispatch_get_nanoseconds();
143 }
144 nsec += delta;
145 if (nsec <= 1) {
146 // -1 is special == DISPATCH_TIME_FOREVER == forever
147 return delta >= 0 ? DISPATCH_TIME_FOREVER : (dispatch_time_t)-2ll;
148 }
149 return (dispatch_time_t)-nsec;
150 }
151
152 uint64_t
153 _dispatch_timeout(dispatch_time_t when)
154 {
155 dispatch_time_t now;
156 if (when == DISPATCH_TIME_FOREVER) {
157 return DISPATCH_TIME_FOREVER;
158 }
159 if (when == 0) {
160 return 0;
161 }
162 if ((int64_t)when < 0) {
163 when = (dispatch_time_t)-(int64_t)when;
164 now = _dispatch_get_nanoseconds();
165 return now >= when ? 0 : when - now;
166 }
167 now = _dispatch_absolute_time();
168 return now >= when ? 0 : _dispatch_time_mach2nano(when - now);
169 }
170
171 uint64_t
172 _dispatch_time_nanoseconds_since_epoch(dispatch_time_t when)
173 {
174 if (when == DISPATCH_TIME_FOREVER) {
175 return DISPATCH_TIME_FOREVER;
176 }
177 if ((int64_t)when < 0) {
178 // time in nanoseconds since the POSIX epoch already
179 return (uint64_t)-(int64_t)when;
180 }
181 return _dispatch_get_nanoseconds() + _dispatch_timeout(when);
182 }