1/*
2 * librd - Rapid Development C library
3 *
4 * Copyright (c) 2012, Magnus Edenhill
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef _RDTIME_H_
30#define _RDTIME_H_
31
32
33#ifndef TIMEVAL_TO_TIMESPEC
34#define TIMEVAL_TO_TIMESPEC(tv,ts) do { \
35 (ts)->tv_sec = (tv)->tv_sec; \
36 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
37 } while (0)
38
39#define TIMESPEC_TO_TIMEVAL(tv, ts) do { \
40 (tv)->tv_sec = (ts)->tv_sec; \
41 (tv)->tv_usec = (ts)->tv_nsec / 1000; \
42 } while (0)
43#endif
44
45#define TIMESPEC_TO_TS(ts) \
46 (((rd_ts_t)(ts)->tv_sec * 1000000LLU) + ((ts)->tv_nsec / 1000))
47
48#define TS_TO_TIMESPEC(ts,tsx) do { \
49 (ts)->tv_sec = (tsx) / 1000000; \
50 (ts)->tv_nsec = ((tsx) % 1000000) * 1000; \
51 if ((ts)->tv_nsec >= 1000000000LLU) { \
52 (ts)->tv_sec++; \
53 (ts)->tv_nsec -= 1000000000LLU; \
54 } \
55 } while (0)
56
57#define TIMESPEC_CLEAR(ts) ((ts)->tv_sec = (ts)->tv_nsec = 0LLU)
58
59
60#define RD_POLL_INFINITE -1
61#define RD_POLL_NOWAIT 0
62
63
64#if RD_UNITTEST_QPC_OVERRIDES
65 /* Overrides for rd_clock() unittest using QPC on Windows */
66BOOL rd_ut_QueryPerformanceFrequency(_Out_ LARGE_INTEGER * lpFrequency);
67BOOL rd_ut_QueryPerformanceCounter(_Out_ LARGE_INTEGER * lpPerformanceCount);
68#define rd_QueryPerformanceFrequency(IFREQ) rd_ut_QueryPerformanceFrequency(IFREQ)
69#define rd_QueryPerformanceCounter(PC) rd_ut_QueryPerformanceCounter(PC)
70#else
71#define rd_QueryPerformanceFrequency(IFREQ) QueryPerformanceFrequency(IFREQ)
72#define rd_QueryPerformanceCounter(PC) QueryPerformanceCounter(PC)
73#endif
74
75/**
76 * @returns a monotonically increasing clock in microseconds.
77 * @remark There is no monotonic clock on OSX, the system time
78 * is returned instead.
79 */
80static RD_INLINE rd_ts_t rd_clock (void) RD_UNUSED;
81static RD_INLINE rd_ts_t rd_clock (void) {
82#ifdef __APPLE__
83 /* No monotonic clock on Darwin */
84 struct timeval tv;
85 gettimeofday(&tv, NULL);
86 return ((rd_ts_t)tv.tv_sec * 1000000LLU) + (rd_ts_t)tv.tv_usec;
87#elif defined(_MSC_VER)
88 LARGE_INTEGER now;
89 static RD_TLS double freq = 0.0;
90 if (!freq) {
91 LARGE_INTEGER ifreq;
92 rd_QueryPerformanceFrequency(&ifreq);
93 /* Convert frequency to double to avoid overflow in
94 * return statement */
95 freq = (double)ifreq.QuadPart / 1000000.0;
96 }
97 rd_QueryPerformanceCounter(&now);
98 return (rd_ts_t)((double)now.QuadPart / freq);
99#else
100 struct timespec ts;
101 clock_gettime(CLOCK_MONOTONIC, &ts);
102 return ((rd_ts_t)ts.tv_sec * 1000000LLU) +
103 ((rd_ts_t)ts.tv_nsec / 1000LLU);
104#endif
105}
106
107
108/**
109 * @returns UTC wallclock time as number of microseconds since
110 * beginning of the epoch.
111 */
112static RD_INLINE RD_UNUSED rd_ts_t rd_uclock (void) {
113 struct timeval tv;
114 rd_gettimeofday(&tv, NULL);
115 return ((rd_ts_t)tv.tv_sec * 1000000LLU) + (rd_ts_t)tv.tv_usec;
116}
117
118
119
120/**
121 * Thread-safe version of ctime() that strips the trailing newline.
122 */
123static RD_INLINE const char *rd_ctime (const time_t *t) RD_UNUSED;
124static RD_INLINE const char *rd_ctime (const time_t *t) {
125 static RD_TLS char ret[27];
126
127#ifndef _MSC_VER
128 ctime_r(t, ret);
129#else
130 ctime_s(ret, sizeof(ret), t);
131#endif
132 ret[25] = '\0';
133
134 return ret;
135}
136
137
138/**
139 * @brief Initialize an absolute timeout based on the provided \p timeout_ms
140 *
141 * To be used with rd_timeout_adjust().
142 *
143 * Honours RD_POLL_INFINITE, RD_POLL_NOWAIT.
144 *
145 * @returns the absolute timeout which should later be passed
146 * to rd_timeout_adjust().
147 */
148static RD_INLINE rd_ts_t rd_timeout_init (int timeout_ms) {
149 if (timeout_ms == RD_POLL_INFINITE ||
150 timeout_ms == RD_POLL_NOWAIT)
151 return timeout_ms;
152
153 return rd_clock() + (timeout_ms * 1000);
154}
155
156
157/**
158 * @brief Initialize an absolute timespec timeout based on the provided
159 * relative \p timeout_ms.
160 *
161 * To be used with cnd_timedwait_abs().
162 *
163 * Honours RD_POLL_INFITE and RD_POLL_NOWAIT (reflected in tspec.tv_sec).
164 */
165static RD_INLINE void rd_timeout_init_timespec (struct timespec *tspec,
166 int timeout_ms) {
167 if (timeout_ms == RD_POLL_INFINITE ||
168 timeout_ms == RD_POLL_NOWAIT) {
169 tspec->tv_sec = timeout_ms;
170 tspec->tv_nsec = 0;
171 } else {
172 timespec_get(tspec, TIME_UTC);
173 tspec->tv_sec += timeout_ms / 1000;
174 tspec->tv_nsec += (timeout_ms % 1000) * 1000000;
175 if (tspec->tv_nsec >= 1000000000) {
176 tspec->tv_nsec -= 1000000000;
177 tspec->tv_sec++;
178 }
179 }
180}
181
182
183/**
184 * @brief Same as rd_timeout_remains() but with microsecond precision
185 */
186static RD_INLINE rd_ts_t rd_timeout_remains_us (rd_ts_t abs_timeout) {
187 rd_ts_t timeout_us;
188
189 if (abs_timeout == RD_POLL_INFINITE ||
190 abs_timeout == RD_POLL_NOWAIT)
191 return (rd_ts_t)abs_timeout;
192
193 timeout_us = abs_timeout - rd_clock();
194 if (timeout_us <= 0)
195 return RD_POLL_NOWAIT;
196 else
197 return timeout_us;
198}
199
200/**
201 * @returns the remaining timeout for timeout \p abs_timeout previously set
202 * up by rd_timeout_init()
203 *
204 * Honours RD_POLL_INFINITE, RD_POLL_NOWAIT.
205 *
206 * @remark Check explicitly for 0 (NOWAIT) to check if there is
207 * no remaining time to way. Any other value, even negative (INFINITE),
208 * means there is remaining time.
209 * rd_timeout_expired() can be used to check the return value
210 * in a bool fashion.
211 */
212static RD_INLINE int rd_timeout_remains (rd_ts_t abs_timeout) {
213 rd_ts_t timeout_us = rd_timeout_remains_us(abs_timeout);
214
215 if (timeout_us == RD_POLL_INFINITE ||
216 timeout_us == RD_POLL_NOWAIT)
217 return (int)timeout_us;
218
219 /* + 999: Round up to millisecond to
220 * avoid busy-looping during the last
221 * millisecond. */
222 return (int)((timeout_us + 999) / 1000);
223}
224
225/**
226 * @brief Like rd_timeout_remains() but limits the maximum time to \p limit_ms
227 */
228static RD_INLINE int
229rd_timeout_remains_limit (rd_ts_t abs_timeout, int limit_ms) {
230 int timeout_ms = rd_timeout_remains(abs_timeout);
231
232 if (timeout_ms == RD_POLL_INFINITE || timeout_ms > limit_ms)
233 return limit_ms;
234 else
235 return timeout_ms;
236}
237
238
239/**
240 * @returns 1 if the **relative** timeout as returned by rd_timeout_remains()
241 * has timed out / expired, else 0.
242 */
243static RD_INLINE int rd_timeout_expired (int timeout_ms) {
244 return timeout_ms == RD_POLL_NOWAIT;
245}
246
247#endif /* _RDTIME_H_ */
248