1#include "common/sleep.h"
2
3#include <time.h>
4#include <errno.h>
5
6#if defined(OS_DARWIN)
7#include <mach/mach.h>
8#include <mach/mach_time.h>
9#endif
10
11/**
12 * Sleep with nanoseconds precision. Tolerant to signal interruptions
13 *
14 * In case query profiler is turned on, all threads spawned for
15 * query execution are repeatedly interrupted by signals from timer.
16 * Functions for relative sleep (sleep(3), nanosleep(2), etc.) have
17 * problems in this setup and man page for nanosleep(2) suggests
18 * using absolute deadlines, for instance clock_nanosleep(2).
19 */
20void sleepForNanoseconds(uint64_t nanoseconds)
21{
22#if defined(OS_DARWIN)
23 //https://developer.apple.com/library/archive/technotes/tn2169/_index.html
24 //https://dshil.github.io/blog/missed-os-x-clock-guide/
25 static mach_timebase_info_data_t timebase_info = {0};
26 if (timebase_info.denom == 0)
27 mach_timebase_info(&timebase_info);
28
29 uint64_t time_to_wait = nanoseconds * timebase_info.denom / timebase_info.numer;
30 uint64_t now = mach_absolute_time();
31
32 while (mach_wait_until(now + time_to_wait) != KERN_SUCCESS);
33#else
34 constexpr auto clock_type = CLOCK_MONOTONIC;
35
36 struct timespec current_time;
37 clock_gettime(clock_type, &current_time);
38
39 constexpr uint64_t resolution = 1'000'000'000;
40 struct timespec finish_time = current_time;
41
42 finish_time.tv_nsec += nanoseconds % resolution;
43 const uint64_t extra_second = finish_time.tv_nsec / resolution;
44 finish_time.tv_nsec %= resolution;
45
46 finish_time.tv_sec += (nanoseconds / resolution) + extra_second;
47
48 while (clock_nanosleep(clock_type, TIMER_ABSTIME, &finish_time, nullptr) == EINTR);
49#endif
50}
51
52void sleepForMicroseconds(uint64_t microseconds)
53{
54 sleepForNanoseconds(microseconds * 1000);
55}
56
57void sleepForMilliseconds(uint64_t milliseconds)
58{
59 sleepForMicroseconds(milliseconds * 1000);
60}
61
62void sleepForSeconds(uint64_t seconds)
63{
64 sleepForMilliseconds(seconds * 1000);
65}
66