Ruby
2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
hrtime.h
Go to the documentation of this file.
1
#ifndef RB_HRTIME_H
2
#define RB_HRTIME_H
3
#include "
ruby/ruby.h
"
4
#include <time.h>
5
#if defined(HAVE_SYS_TIME_H)
6
# include <sys/time.h>
7
#endif
8
9
/*
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).
13
*
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)
17
*
18
* Current API:
19
*
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
29
*
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.
34
*/
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
39
40
/*
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
43
*/
44
#ifdef MY_RUBY_BUILD_MAY_TIME_TRAVEL
45
typedef
int128_t
rb_hrtime_t
;
46
#else
47
typedef
uint64_t
rb_hrtime_t
;
48
#endif
49
50
/* thread.c */
51
/* returns the value of the monotonic clock (if available) */
52
rb_hrtime_t
rb_hrtime_now
(
void
);
53
54
/*
55
* multiply @a and @b with overflow check and return the
56
* (clamped to RB_HRTIME_MAX) result.
57
*/
58
static
inline
rb_hrtime_t
59
rb_hrtime_mul(
rb_hrtime_t
a,
rb_hrtime_t
b)
60
{
61
rb_hrtime_t
c;
62
63
#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
64
if
(__builtin_mul_overflow(a, b, &c))
65
return
RB_HRTIME_MAX
;
66
#else
67
if
(b != 0 && a >
RB_HRTIME_MAX
/ b)
/* overflow */
68
return
RB_HRTIME_MAX
;
69
c = a * b;
70
#endif
71
return
c;
72
}
73
74
/*
75
* add @a and @b with overflow check and return the
76
* (clamped to RB_HRTIME_MAX) result.
77
*/
78
static
inline
rb_hrtime_t
79
rb_hrtime_add(
rb_hrtime_t
a,
rb_hrtime_t
b)
80
{
81
rb_hrtime_t
c;
82
83
#ifdef HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
84
if
(__builtin_add_overflow(a, b, &c))
85
return
RB_HRTIME_MAX
;
86
#else
87
c = a + b;
88
if
(c < a)
/* overflow */
89
return
RB_HRTIME_MAX
;
90
#endif
91
return
c;
92
}
93
94
/*
95
* convert a timeval struct to rb_hrtime_t, clamping at RB_HRTIME_MAX
96
*/
97
static
inline
rb_hrtime_t
98
rb_timeval2hrtime(
const
struct
timeval
*tv)
99
{
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
);
102
103
return
rb_hrtime_add(s, u);
104
}
105
106
/*
107
* convert a timespec struct to rb_hrtime_t, clamping at RB_HRTIME_MAX
108
*/
109
static
inline
rb_hrtime_t
110
rb_timespec2hrtime(
const
struct
timespec
*ts)
111
{
112
rb_hrtime_t
s = rb_hrtime_mul((
rb_hrtime_t
)ts->
tv_sec
,
RB_HRTIME_PER_SEC
);
113
114
return
rb_hrtime_add(s, (
rb_hrtime_t
)ts->
tv_nsec
);
115
}
116
117
/*
118
* convert a millisecond value to rb_hrtime_t, clamping at RB_HRTIME_MAX
119
*/
120
static
inline
rb_hrtime_t
121
rb_msec2hrtime(
unsigned
long
msec)
122
{
123
return
rb_hrtime_mul((
rb_hrtime_t
)msec,
RB_HRTIME_PER_MSEC
);
124
}
125
126
/*
127
* convert a time_t value to rb_hrtime_t, clamping at RB_HRTIME_MAX
128
* Negative values will be clamped at 0.
129
*/
130
static
inline
rb_hrtime_t
131
rb_sec2hrtime(
time_t
sec)
132
{
133
if
(sec <= 0)
return
0;
134
135
return
rb_hrtime_mul((
rb_hrtime_t
)sec,
RB_HRTIME_PER_SEC
);
136
}
137
138
/*
139
* convert a rb_hrtime_t value to a timespec, suitable for calling
140
* functions like ppoll(2) or kevent(2)
141
*/
142
static
inline
struct
timespec
*
143
rb_hrtime2timespec(
struct
timespec
*ts,
const
rb_hrtime_t
*hrt)
144
{
145
if
(hrt) {
146
ts->
tv_sec
= (
time_t
)(*hrt /
RB_HRTIME_PER_SEC
);
147
ts->
tv_nsec
= (
int32_t
)(*hrt %
RB_HRTIME_PER_SEC
);
148
return
ts;
149
}
150
return
0;
151
}
152
153
/*
154
* convert a rb_hrtime_t value to a timeval, suitable for calling
155
* functions like select(2)
156
*/
157
static
inline
struct
timeval
*
158
rb_hrtime2timeval(
struct
timeval
*tv,
const
rb_hrtime_t
*hrt)
159
{
160
if
(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
);
163
164
return
tv;
165
}
166
return
0;
167
}
168
#endif
/* RB_HRTIME_H */
RB_HRTIME_PER_SEC
#define RB_HRTIME_PER_SEC
Definition:
hrtime.h:37
rb_hrtime_now
rb_hrtime_t rb_hrtime_now(void)
Definition:
thread.c:1229
rb_hrtime_t
uint64_t rb_hrtime_t
Definition:
hrtime.h:47
RB_HRTIME_MAX
#define RB_HRTIME_MAX
Definition:
hrtime.h:38
uint64_t
unsigned long long uint64_t
Definition:
sha2.h:102
ruby.h
timespec::tv_nsec
long tv_nsec
Definition:
missing.h:62
timespec::tv_sec
time_t tv_sec
Definition:
missing.h:61
int32_t
__int32_t int32_t
Definition:
rb_mjit_min_header-2.7.2.h:1174
RB_HRTIME_PER_MSEC
#define RB_HRTIME_PER_MSEC
Definition:
hrtime.h:36
timeval::tv_sec
time_t tv_sec
Definition:
missing.h:54
timeval::tv_usec
long tv_usec
Definition:
missing.h:55
timeval
Definition:
missing.h:53
RB_HRTIME_PER_USEC
#define RB_HRTIME_PER_USEC
Definition:
hrtime.h:35
timespec
Definition:
missing.h:60
time_t
long time_t
Definition:
rb_mjit_min_header-2.7.2.h:1235
Generated by
1.8.20