5 #if defined(HAVE_SYS_TIME_H)
10 * Hi-res monotonic clock. It is currently nsec resolution, which has over
11 * 500 years of range (with an unsigned 64-bit integer). Developers
12 * targeting small systems may try 32-bit and low-resolution (milliseconds).
14 * TBD: Is nsec even necessary? usec resolution seems enough for userspace
15 * and it'll be suitable for use with devices lasting over 500,000 years
16 * (maybe some devices designed for long-term space travel)
20 * * rb_hrtime_now - current clock value (monotonic if available)
21 * * rb_hrtime_mul - multiply with overflow check
22 * * rb_hrtime_add - add with overflow check
23 * * rb_timeval2hrtime - convert from timeval
24 * * rb_timespec2hrtime - convert from timespec
25 * * rb_msec2hrtime - convert from millisecond
26 * * rb_sec2hrtime - convert from time_t (seconds)
27 * * rb_hrtime2timeval - convert to timeval
28 * * rb_hrtime2timespec - convert to timespec
30 * Note: no conversion to milliseconds is provided here because different
31 * functions have different limits (e.g. epoll_wait vs w32_wait_events).
32 * So we provide RB_HRTIME_PER_MSEC and similar macros for implementing
33 * this for each use case.
35 #define RB_HRTIME_PER_USEC ((rb_hrtime_t)1000)
36 #define RB_HRTIME_PER_MSEC (RB_HRTIME_PER_USEC * (rb_hrtime_t)1000)
37 #define RB_HRTIME_PER_SEC (RB_HRTIME_PER_MSEC * (rb_hrtime_t)1000)
38 #define RB_HRTIME_MAX UINT64_MAX
41 * Lets try to support time travelers. Lets assume anybody with a time machine
42 * also has access to a modern gcc or clang with 128-bit int support
44 #ifdef MY_RUBY_BUILD_MAY_TIME_TRAVEL
45 typedef int128_t rb_hrtime_t
;
47 typedef uint64_t rb_hrtime_t
;
51 /* returns the value of the monotonic clock (if available) */
52 rb_hrtime_t
rb_hrtime_now(void);
55 * multiply @a and @b with overflow check and return the
56 * (clamped to RB_HRTIME_MAX) result.
58 static inline rb_hrtime_t
59 rb_hrtime_mul(rb_hrtime_t a
, rb_hrtime_t b
)
63 #ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
64 if (__builtin_mul_overflow(a
, b
, &c
))
67 if (b
!= 0 && a
> RB_HRTIME_MAX
/ b
) /* overflow */
75 * add @a and @b with overflow check and return the
76 * (clamped to RB_HRTIME_MAX) result.
78 static inline rb_hrtime_t
79 rb_hrtime_add(rb_hrtime_t a
, rb_hrtime_t b
)
83 #ifdef HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
84 if (__builtin_add_overflow(a
, b
, &c
))
88 if (c
< a
) /* overflow */
95 * convert a timeval struct to rb_hrtime_t, clamping at RB_HRTIME_MAX
97 static inline rb_hrtime_t
98 rb_timeval2hrtime(const struct timeval
*tv
)
100 rb_hrtime_t s
= rb_hrtime_mul((rb_hrtime_t
)tv
->tv_sec
, RB_HRTIME_PER_SEC
);
101 rb_hrtime_t u
= rb_hrtime_mul((rb_hrtime_t
)tv
->tv_usec
, RB_HRTIME_PER_USEC
);
103 return rb_hrtime_add(s
, u
);
107 * convert a timespec struct to rb_hrtime_t, clamping at RB_HRTIME_MAX
109 static inline rb_hrtime_t
110 rb_timespec2hrtime(const struct timespec
*ts
)
112 rb_hrtime_t s
= rb_hrtime_mul((rb_hrtime_t
)ts
->tv_sec
, RB_HRTIME_PER_SEC
);
114 return rb_hrtime_add(s
, (rb_hrtime_t
)ts
->tv_nsec
);
118 * convert a millisecond value to rb_hrtime_t, clamping at RB_HRTIME_MAX
120 static inline rb_hrtime_t
121 rb_msec2hrtime(unsigned long msec
)
123 return rb_hrtime_mul((rb_hrtime_t
)msec
, RB_HRTIME_PER_MSEC
);
127 * convert a time_t value to rb_hrtime_t, clamping at RB_HRTIME_MAX
128 * Negative values will be clamped at 0.
130 static inline rb_hrtime_t
131 rb_sec2hrtime(time_t sec
)
133 if (sec
<= 0) return 0;
135 return rb_hrtime_mul((rb_hrtime_t
)sec
, RB_HRTIME_PER_SEC
);
139 * convert a rb_hrtime_t value to a timespec, suitable for calling
140 * functions like ppoll(2) or kevent(2)
142 static inline struct timespec
*
143 rb_hrtime2timespec(struct timespec
*ts
, const rb_hrtime_t
*hrt
)
146 ts
->tv_sec
= (time_t)(*hrt
/ RB_HRTIME_PER_SEC
);
147 ts
->tv_nsec
= (int32_t)(*hrt
% RB_HRTIME_PER_SEC
);
154 * convert a rb_hrtime_t value to a timeval, suitable for calling
155 * functions like select(2)
157 static inline struct timeval
*
158 rb_hrtime2timeval(struct timeval
*tv
, const rb_hrtime_t
*hrt
)
161 tv
->tv_sec
= (time_t)(*hrt
/ RB_HRTIME_PER_SEC
);
162 tv
->tv_usec
= (int32_t)((*hrt
% RB_HRTIME_PER_SEC
)/RB_HRTIME_PER_USEC
);
168 #endif /* RB_HRTIME_H */