Allow the time remaining parameter to nanosleep to be null
[folly.git] / folly / portability / Time.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/portability/Time.h>
18 #include <folly/Likely.h>
19
20 #include <assert.h>
21
22 #include <chrono>
23
24 template <typename _Rep, typename _Period>
25 static void duration_to_ts(
26     std::chrono::duration<_Rep, _Period> d,
27     struct timespec* ts) {
28   ts->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
29   ts->tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(
30                     d % std::chrono::seconds(1))
31                     .count();
32 }
33
34 #if !FOLLY_HAVE_CLOCK_GETTIME
35 #if __MACH__
36 #include <errno.h>
37 #include <mach/mach_init.h>
38 #include <mach/mach_port.h>
39 #include <mach/mach_time.h>
40 #include <mach/mach_types.h>
41 #include <mach/task.h>
42 #include <mach/thread_act.h>
43 #include <mach/vm_map.h>
44
45 static std::chrono::nanoseconds time_value_to_ns(time_value_t t) {
46   return std::chrono::seconds(t.seconds) +
47       std::chrono::microseconds(t.microseconds);
48 }
49
50 static int clock_process_cputime(struct timespec* ts) {
51   // Get CPU usage for live threads.
52   task_thread_times_info thread_times_info;
53   mach_msg_type_number_t thread_times_info_count = TASK_THREAD_TIMES_INFO_COUNT;
54   kern_return_t kern_result = task_info(
55       mach_task_self(),
56       TASK_THREAD_TIMES_INFO,
57       (thread_info_t)&thread_times_info,
58       &thread_times_info_count);
59   if (UNLIKELY(kern_result != KERN_SUCCESS)) {
60     return -1;
61   }
62
63   // Get CPU usage for terminated threads.
64   mach_task_basic_info task_basic_info;
65   mach_msg_type_number_t task_basic_info_count = MACH_TASK_BASIC_INFO_COUNT;
66   kern_result = task_info(
67       mach_task_self(),
68       MACH_TASK_BASIC_INFO,
69       (thread_info_t)&task_basic_info,
70       &task_basic_info_count);
71   if (UNLIKELY(kern_result != KERN_SUCCESS)) {
72     return -1;
73   }
74
75   auto cputime = time_value_to_ns(thread_times_info.user_time) +
76       time_value_to_ns(thread_times_info.system_time) +
77       time_value_to_ns(task_basic_info.user_time) +
78       time_value_to_ns(task_basic_info.system_time);
79   duration_to_ts(cputime, ts);
80   return 0;
81 }
82
83 static int clock_thread_cputime(struct timespec* ts) {
84   mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
85   thread_basic_info_data_t thread_info_data;
86   thread_act_t thread = mach_thread_self();
87   kern_return_t kern_result = thread_info(
88       thread, THREAD_BASIC_INFO, (thread_info_t)&thread_info_data, &count);
89   mach_port_deallocate(mach_task_self(), thread);
90   if (UNLIKELY(kern_result != KERN_SUCCESS)) {
91     return -1;
92   }
93   auto cputime = time_value_to_ns(thread_info_data.system_time) +
94       time_value_to_ns(thread_info_data.user_time);
95   duration_to_ts(cputime, ts);
96   return 0;
97 }
98
99 int clock_gettime(clockid_t clk_id, struct timespec* ts) {
100   switch (clk_id) {
101     case CLOCK_REALTIME: {
102       auto now = std::chrono::system_clock::now().time_since_epoch();
103       duration_to_ts(now, ts);
104       return 0;
105     }
106     case CLOCK_MONOTONIC: {
107       auto now = std::chrono::steady_clock::now().time_since_epoch();
108       duration_to_ts(now, ts);
109       return 0;
110     }
111     case CLOCK_PROCESS_CPUTIME_ID:
112       return clock_process_cputime(ts);
113     case CLOCK_THREAD_CPUTIME_ID:
114       return clock_thread_cputime(ts);
115     default:
116       errno = EINVAL;
117       return -1;
118   }
119 }
120
121 int clock_getres(clockid_t clk_id, struct timespec* ts) {
122   if (clk_id != CLOCK_MONOTONIC) {
123     return -1;
124   }
125
126   static auto info = [] {
127     static mach_timebase_info_data_t info;
128     auto result = (mach_timebase_info(&info) == KERN_SUCCESS) ? &info : nullptr;
129     assert(result);
130     return result;
131   }();
132
133   ts->tv_sec = 0;
134   ts->tv_nsec = info->numer / info->denom;
135
136   return 0;
137 }
138 #elif defined(_WIN32)
139 #include <errno.h>
140 #include <locale.h>
141 #include <stdint.h>
142 #include <stdlib.h>
143
144 #include <folly/portability/Windows.h>
145
146 using unsigned_nanos = std::chrono::duration<uint64_t, std::nano>;
147
148 static unsigned_nanos filetimeToUnsignedNanos(FILETIME ft) {
149   ULARGE_INTEGER i;
150   i.HighPart = ft.dwHighDateTime;
151   i.LowPart = ft.dwLowDateTime;
152
153   // FILETIMEs are in units of 100ns.
154   return unsigned_nanos(i.QuadPart * 100);
155 };
156
157 static LARGE_INTEGER performanceFrequency() {
158   static auto result = [] {
159     LARGE_INTEGER freq;
160     // On Windows XP or later, this will never fail.
161     BOOL res = QueryPerformanceFrequency(&freq);
162     assert(res);
163     return freq;
164   }();
165   return result;
166 }
167
168 extern "C" int clock_getres(clockid_t clock_id, struct timespec* res) {
169   if (!res) {
170     errno = EFAULT;
171     return -1;
172   }
173
174   switch (clock_id) {
175     case CLOCK_MONOTONIC: {
176       LARGE_INTEGER freq = performanceFrequency();
177       if (freq.QuadPart == -1) {
178         errno = EINVAL;
179         return -1;
180       }
181
182       static constexpr size_t kNsPerSec = 1000000000;
183
184       res->tv_sec = 0;
185       res->tv_nsec = (long)((kNsPerSec + (freq.QuadPart >> 1)) / freq.QuadPart);
186       if (res->tv_nsec < 1) {
187         res->tv_nsec = 1;
188       }
189
190       return 0;
191     }
192
193     case CLOCK_REALTIME:
194     case CLOCK_PROCESS_CPUTIME_ID:
195     case CLOCK_THREAD_CPUTIME_ID: {
196       DWORD adj, timeIncrement;
197       BOOL adjDisabled;
198       if (!GetSystemTimeAdjustment(&adj, &timeIncrement, &adjDisabled)) {
199         errno = EINVAL;
200         return -1;
201       }
202
203       res->tv_sec = 0;
204       res->tv_nsec = timeIncrement * 100;
205       return 0;
206     }
207
208     default:
209       errno = EINVAL;
210       return -1;
211   }
212 }
213
214 extern "C" int clock_gettime(clockid_t clock_id, struct timespec* tp) {
215   if (!tp) {
216     errno = EFAULT;
217     return -1;
218   }
219
220   const auto unanosToTimespec = [](timespec* tp, unsigned_nanos t) -> int {
221     static constexpr unsigned_nanos one_sec(std::chrono::seconds(1));
222     tp->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(t).count();
223     tp->tv_nsec = (t % one_sec).count();
224     return 0;
225   };
226
227   FILETIME createTime, exitTime, kernalTime, userTime;
228   switch (clock_id) {
229     case CLOCK_REALTIME: {
230       auto now = std::chrono::system_clock::now().time_since_epoch();
231       duration_to_ts(now, tp);
232       return 0;
233     }
234     case CLOCK_MONOTONIC: {
235       auto now = std::chrono::steady_clock::now().time_since_epoch();
236       duration_to_ts(now, tp);
237       return 0;
238     }
239     case CLOCK_PROCESS_CPUTIME_ID: {
240       if (!GetProcessTimes(
241               GetCurrentProcess(),
242               &createTime,
243               &exitTime,
244               &kernalTime,
245               &userTime)) {
246         errno = EINVAL;
247         return -1;
248       }
249
250       return unanosToTimespec(
251           tp,
252           filetimeToUnsignedNanos(kernalTime) +
253               filetimeToUnsignedNanos(userTime));
254     }
255     case CLOCK_THREAD_CPUTIME_ID: {
256       if (!GetThreadTimes(
257               GetCurrentThread(),
258               &createTime,
259               &exitTime,
260               &kernalTime,
261               &userTime)) {
262         errno = EINVAL;
263         return -1;
264       }
265
266       return unanosToTimespec(
267           tp,
268           filetimeToUnsignedNanos(kernalTime) +
269               filetimeToUnsignedNanos(userTime));
270     }
271
272     default:
273       errno = EINVAL;
274       return -1;
275   }
276 }
277 #else
278 #error No clock_gettime(3) compatibility wrapper available for this platform.
279 #endif
280 #endif
281
282 #ifdef _WIN32
283 #include <iomanip>
284 #include <sstream>
285
286 #include <folly/portability/Windows.h>
287
288 extern "C" {
289 char* asctime_r(const tm* tm, char* buf) {
290   char tmpBuf[64];
291   if (asctime_s(tmpBuf, tm)) {
292     return nullptr;
293   }
294   // Nothing we can do if the buff is to small :(
295   return strcpy(buf, tmpBuf);
296 }
297
298 char* ctime_r(const time_t* t, char* buf) {
299   char tmpBuf[64];
300   if (ctime_s(tmpBuf, 64, t)) {
301     return nullptr;
302   }
303   // Nothing we can do if the buff is to small :(
304   return strcpy(buf, tmpBuf);
305 }
306
307 tm* gmtime_r(const time_t* t, tm* res) {
308   if (!gmtime_s(res, t)) {
309     return res;
310   }
311   return nullptr;
312 }
313
314 tm* localtime_r(const time_t* t, tm* o) {
315   if (!localtime_s(o, t)) {
316     return o;
317   }
318   return nullptr;
319 }
320
321 int nanosleep(const struct timespec* request, struct timespec* remain) {
322   Sleep((DWORD)((request->tv_sec * 1000) + (request->tv_nsec / 1000000)));
323   if (remain != nullptr) {
324     remain->tv_nsec = 0;
325     remain->tv_sec = 0;
326   }
327   return 0;
328 }
329
330 char* strptime(const char* __restrict s,
331                const char* __restrict f,
332                struct tm* __restrict tm) {
333   // Isn't the C++ standard lib nice? std::get_time is defined such that its
334   // format parameters are the exact same as strptime. Of course, we have to
335   // create a string stream first, and imbue it with the current C locale, and
336   // we also have to make sure we return the right things if it fails, or
337   // if it succeeds, but this is still far simpler an implementation than any
338   // of the versions in any of the C standard libraries.
339   std::istringstream input(s);
340   input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
341   input >> std::get_time(tm, f);
342   if (input.fail()) {
343     return nullptr;
344   }
345   return const_cast<char*>(s + input.tellg());
346 }
347 }
348 #endif