/src/librabbitmq/librabbitmq/amqp_time.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2007 - 2021, Alan Antonuk and the rabbitmq-c contributors. |
2 | | // SPDX-License-Identifier: mit |
3 | | |
4 | | #include "amqp_time.h" |
5 | | #include "rabbitmq-c/amqp.h" |
6 | | #include <assert.h> |
7 | | #include <limits.h> |
8 | | #include <string.h> |
9 | | |
10 | | #if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || \ |
11 | | defined(__MINGW32__) || defined(__MINGW64__)) |
12 | | #define AMQP_WIN_TIMER_API |
13 | | #elif (defined(machintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) |
14 | | #define AMQP_MAC_TIMER_API |
15 | | #else |
16 | | #define AMQP_POSIX_TIMER_API |
17 | | #endif |
18 | | |
19 | | #ifdef AMQP_WIN_TIMER_API |
20 | | #ifndef WIN32_LEAN_AND_MEAN |
21 | | #define WIN32_LEAN_AND_MEAN |
22 | | #endif |
23 | | #include <windows.h> |
24 | | |
25 | | uint64_t amqp_get_monotonic_timestamp(void) { |
26 | | static double NS_PER_COUNT = 0; |
27 | | LARGE_INTEGER perf_count; |
28 | | |
29 | | if (0 == NS_PER_COUNT) { |
30 | | LARGE_INTEGER perf_frequency; |
31 | | if (!QueryPerformanceFrequency(&perf_frequency)) { |
32 | | return 0; |
33 | | } |
34 | | NS_PER_COUNT = (double)AMQP_NS_PER_S / perf_frequency.QuadPart; |
35 | | } |
36 | | |
37 | | if (!QueryPerformanceCounter(&perf_count)) { |
38 | | return 0; |
39 | | } |
40 | | |
41 | | return (uint64_t)(perf_count.QuadPart * NS_PER_COUNT); |
42 | | } |
43 | | #endif /* AMQP_WIN_TIMER_API */ |
44 | | |
45 | | #ifdef AMQP_MAC_TIMER_API |
46 | | #include <mach/mach_time.h> |
47 | | |
48 | | uint64_t amqp_get_monotonic_timestamp(void) { |
49 | | static mach_timebase_info_data_t s_timebase = {0, 0}; |
50 | | uint64_t timestamp; |
51 | | |
52 | | timestamp = mach_absolute_time(); |
53 | | |
54 | | if (s_timebase.denom == 0) { |
55 | | mach_timebase_info(&s_timebase); |
56 | | if (0 == s_timebase.denom) { |
57 | | return 0; |
58 | | } |
59 | | } |
60 | | |
61 | | timestamp *= (uint64_t)s_timebase.numer; |
62 | | timestamp /= (uint64_t)s_timebase.denom; |
63 | | |
64 | | return timestamp; |
65 | | } |
66 | | #endif /* AMQP_MAC_TIMER_API */ |
67 | | |
68 | | #ifdef AMQP_POSIX_TIMER_API |
69 | | #include <time.h> |
70 | | |
71 | 0 | uint64_t amqp_get_monotonic_timestamp(void) { |
72 | | #ifdef __hpux |
73 | | return (uint64_t)gethrtime(); |
74 | | #else |
75 | 0 | struct timespec tp; |
76 | 0 | if (-1 == clock_gettime(CLOCK_MONOTONIC, &tp)) { |
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | 0 | return ((uint64_t)tp.tv_sec * AMQP_NS_PER_S + (uint64_t)tp.tv_nsec); |
81 | 0 | #endif |
82 | 0 | } |
83 | | #endif /* AMQP_POSIX_TIMER_API */ |
84 | | |
85 | 0 | int amqp_time_from_now(amqp_time_t *time, const struct timeval *timeout) { |
86 | 0 | uint64_t now_ns; |
87 | 0 | uint64_t delta_ns; |
88 | |
|
89 | 0 | assert(NULL != time); |
90 | | |
91 | 0 | if (NULL == timeout) { |
92 | 0 | *time = amqp_time_infinite(); |
93 | 0 | return AMQP_STATUS_OK; |
94 | 0 | } |
95 | | |
96 | 0 | if (timeout->tv_sec < 0 || timeout->tv_usec < 0) { |
97 | 0 | return AMQP_STATUS_INVALID_PARAMETER; |
98 | 0 | } |
99 | | |
100 | 0 | delta_ns = (uint64_t)timeout->tv_sec * AMQP_NS_PER_S + |
101 | 0 | (uint64_t)timeout->tv_usec * AMQP_NS_PER_US; |
102 | |
|
103 | 0 | now_ns = amqp_get_monotonic_timestamp(); |
104 | 0 | if (0 == now_ns) { |
105 | 0 | return AMQP_STATUS_TIMER_FAILURE; |
106 | 0 | } |
107 | | |
108 | 0 | time->time_point_ns = now_ns + delta_ns; |
109 | 0 | if (now_ns > time->time_point_ns || delta_ns > time->time_point_ns) { |
110 | 0 | return AMQP_STATUS_INVALID_PARAMETER; |
111 | 0 | } |
112 | | |
113 | 0 | return AMQP_STATUS_OK; |
114 | 0 | } |
115 | | |
116 | 0 | int amqp_time_s_from_now(amqp_time_t *time, int seconds) { |
117 | 0 | uint64_t now_ns; |
118 | 0 | uint64_t delta_ns; |
119 | 0 | assert(NULL != time); |
120 | | |
121 | 0 | if (0 >= seconds) { |
122 | 0 | *time = amqp_time_infinite(); |
123 | 0 | return AMQP_STATUS_OK; |
124 | 0 | } |
125 | | |
126 | 0 | now_ns = amqp_get_monotonic_timestamp(); |
127 | 0 | if (0 == now_ns) { |
128 | 0 | return AMQP_STATUS_TIMER_FAILURE; |
129 | 0 | } |
130 | | |
131 | 0 | delta_ns = (uint64_t)seconds * AMQP_NS_PER_S; |
132 | 0 | time->time_point_ns = now_ns + delta_ns; |
133 | 0 | if (now_ns > time->time_point_ns || delta_ns > time->time_point_ns) { |
134 | 0 | return AMQP_STATUS_INVALID_PARAMETER; |
135 | 0 | } |
136 | | |
137 | 0 | return AMQP_STATUS_OK; |
138 | 0 | } |
139 | | |
140 | 0 | amqp_time_t amqp_time_infinite(void) { |
141 | 0 | amqp_time_t time; |
142 | 0 | time.time_point_ns = UINT64_MAX; |
143 | 0 | return time; |
144 | 0 | } |
145 | | |
146 | 0 | int amqp_time_ms_until(amqp_time_t time) { |
147 | 0 | uint64_t now_ns; |
148 | 0 | uint64_t delta_ns; |
149 | 0 | int left_ms; |
150 | |
|
151 | 0 | if (UINT64_MAX == time.time_point_ns) { |
152 | 0 | return -1; |
153 | 0 | } |
154 | 0 | if (0 == time.time_point_ns) { |
155 | 0 | return 0; |
156 | 0 | } |
157 | | |
158 | 0 | now_ns = amqp_get_monotonic_timestamp(); |
159 | 0 | if (0 == now_ns) { |
160 | 0 | return AMQP_STATUS_TIMER_FAILURE; |
161 | 0 | } |
162 | | |
163 | 0 | if (now_ns >= time.time_point_ns) { |
164 | 0 | return 0; |
165 | 0 | } |
166 | | |
167 | 0 | delta_ns = time.time_point_ns - now_ns; |
168 | 0 | left_ms = (int)(delta_ns / AMQP_NS_PER_MS); |
169 | |
|
170 | 0 | return left_ms; |
171 | 0 | } |
172 | | |
173 | | int amqp_time_tv_until(amqp_time_t time, struct timeval *in, |
174 | 0 | struct timeval **out) { |
175 | 0 | uint64_t now_ns; |
176 | 0 | uint64_t delta_ns; |
177 | |
|
178 | 0 | assert(in != NULL); |
179 | 0 | if (UINT64_MAX == time.time_point_ns) { |
180 | 0 | *out = NULL; |
181 | 0 | return AMQP_STATUS_OK; |
182 | 0 | } |
183 | 0 | if (0 == time.time_point_ns) { |
184 | 0 | in->tv_sec = 0; |
185 | 0 | in->tv_usec = 0; |
186 | 0 | *out = in; |
187 | 0 | return AMQP_STATUS_OK; |
188 | 0 | } |
189 | | |
190 | 0 | now_ns = amqp_get_monotonic_timestamp(); |
191 | 0 | if (0 == now_ns) { |
192 | 0 | return AMQP_STATUS_TIMER_FAILURE; |
193 | 0 | } |
194 | | |
195 | 0 | if (now_ns >= time.time_point_ns) { |
196 | 0 | in->tv_sec = 0; |
197 | 0 | in->tv_usec = 0; |
198 | 0 | *out = in; |
199 | 0 | return AMQP_STATUS_OK; |
200 | 0 | } |
201 | | |
202 | 0 | delta_ns = time.time_point_ns - now_ns; |
203 | 0 | in->tv_sec = (int)(delta_ns / AMQP_NS_PER_S); |
204 | 0 | in->tv_usec = (int)((delta_ns % AMQP_NS_PER_S) / AMQP_NS_PER_US); |
205 | 0 | *out = in; |
206 | |
|
207 | 0 | return AMQP_STATUS_OK; |
208 | 0 | } |
209 | | |
210 | 0 | int amqp_time_has_past(amqp_time_t time) { |
211 | 0 | uint64_t now_ns; |
212 | 0 | if (UINT64_MAX == time.time_point_ns) { |
213 | 0 | return AMQP_STATUS_OK; |
214 | 0 | } |
215 | | |
216 | 0 | now_ns = amqp_get_monotonic_timestamp(); |
217 | 0 | if (0 == now_ns) { |
218 | 0 | return AMQP_STATUS_TIMER_FAILURE; |
219 | 0 | } |
220 | | |
221 | 0 | if (now_ns > time.time_point_ns) { |
222 | 0 | return AMQP_STATUS_TIMEOUT; |
223 | 0 | } |
224 | 0 | return AMQP_STATUS_OK; |
225 | 0 | } |
226 | | |
227 | 0 | amqp_time_t amqp_time_first(amqp_time_t l, amqp_time_t r) { |
228 | 0 | if (l.time_point_ns < r.time_point_ns) { |
229 | 0 | return l; |
230 | 0 | } |
231 | 0 | return r; |
232 | 0 | } |
233 | | |
234 | 0 | int amqp_time_equal(amqp_time_t l, amqp_time_t r) { |
235 | 0 | return l.time_point_ns == r.time_point_ns; |
236 | 0 | } |