]>
Commit | Line | Data |
---|---|---|
7790a2d6 DL |
1 | /* |
2 | * Copyright (c) 2017 David Lamparter, for NetDEF, Inc. | |
3 | * | |
4 | * Permission to use, copy, modify, and distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #ifndef _FRR_MONOTIME_H | |
18 | #define _FRR_MONOTIME_H | |
19 | ||
20 | #include <stdint.h> | |
21 | #include <time.h> | |
22 | #include <sys/time.h> | |
23 | ||
5e244469 RW |
24 | #ifdef __cplusplus |
25 | extern "C" { | |
26 | #endif | |
27 | ||
2c76ba43 DL |
28 | struct fbuf; |
29 | struct printfrr_eargs; | |
30 | ||
7790a2d6 DL |
31 | #ifndef TIMESPEC_TO_TIMEVAL |
32 | /* should be in sys/time.h on BSD & Linux libcs */ | |
d62a17ae | 33 | #define TIMESPEC_TO_TIMEVAL(tv, ts) \ |
34 | do { \ | |
35 | (tv)->tv_sec = (ts)->tv_sec; \ | |
36 | (tv)->tv_usec = (ts)->tv_nsec / 1000; \ | |
37 | } while (0) | |
7790a2d6 | 38 | #endif |
39cea822 DL |
39 | #ifndef TIMEVAL_TO_TIMESPEC |
40 | /* should be in sys/time.h on BSD & Linux libcs */ | |
d62a17ae | 41 | #define TIMEVAL_TO_TIMESPEC(tv, ts) \ |
42 | do { \ | |
43 | (ts)->tv_sec = (tv)->tv_sec; \ | |
44 | (ts)->tv_nsec = (tv)->tv_usec * 1000; \ | |
45 | } while (0) | |
39cea822 | 46 | #endif |
7790a2d6 | 47 | |
2c76ba43 DL |
48 | /* Linux/glibc is sadly missing these timespec helpers */ |
49 | #ifndef timespecadd | |
50 | #define timespecadd(tsp, usp, vsp) \ | |
51 | do { \ | |
52 | (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ | |
53 | (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ | |
54 | if ((vsp)->tv_nsec >= 1000000000L) { \ | |
55 | (vsp)->tv_sec++; \ | |
56 | (vsp)->tv_nsec -= 1000000000L; \ | |
57 | } \ | |
58 | } while (0) | |
59 | #endif | |
60 | ||
61 | #ifndef timespecsub | |
62 | #define timespecsub(tsp, usp, vsp) \ | |
63 | do { \ | |
64 | (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ | |
65 | (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ | |
66 | if ((vsp)->tv_nsec < 0) { \ | |
67 | (vsp)->tv_sec--; \ | |
68 | (vsp)->tv_nsec += 1000000000L; \ | |
69 | } \ | |
70 | } while (0) | |
71 | #endif | |
72 | ||
7790a2d6 DL |
73 | static inline time_t monotime(struct timeval *tvo) |
74 | { | |
d62a17ae | 75 | struct timespec ts; |
7790a2d6 | 76 | |
d62a17ae | 77 | clock_gettime(CLOCK_MONOTONIC, &ts); |
78 | if (tvo) { | |
79 | TIMESPEC_TO_TIMEVAL(tvo, &ts); | |
80 | } | |
81 | return ts.tv_sec; | |
7790a2d6 DL |
82 | } |
83 | ||
bddfc297 DS |
84 | #define ONE_DAY_SECOND (60 * 60 * 24) |
85 | #define ONE_WEEK_SECOND (ONE_DAY_SECOND * 7) | |
86 | #define ONE_YEAR_SECOND (ONE_DAY_SECOND * 365) | |
99a6a31e | 87 | |
7790a2d6 DL |
88 | /* the following two return microseconds, not time_t! |
89 | * | |
90 | * also, they're negative forms of each other, but having both makes the | |
91 | * code more readable | |
92 | */ | |
93 | static inline int64_t monotime_since(const struct timeval *ref, | |
d62a17ae | 94 | struct timeval *out) |
7790a2d6 | 95 | { |
d62a17ae | 96 | struct timeval tv; |
97 | monotime(&tv); | |
98 | timersub(&tv, ref, &tv); | |
99 | if (out) | |
100 | *out = tv; | |
101 | return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec; | |
7790a2d6 DL |
102 | } |
103 | ||
104 | static inline int64_t monotime_until(const struct timeval *ref, | |
d62a17ae | 105 | struct timeval *out) |
7790a2d6 | 106 | { |
d62a17ae | 107 | struct timeval tv; |
108 | monotime(&tv); | |
109 | timersub(ref, &tv, &tv); | |
110 | if (out) | |
111 | *out = tv; | |
112 | return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec; | |
7790a2d6 DL |
113 | } |
114 | ||
8defc5be DL |
115 | static inline time_t monotime_to_realtime(const struct timeval *mono, |
116 | struct timeval *realout) | |
117 | { | |
118 | struct timeval delta, real; | |
119 | ||
120 | monotime_since(mono, &delta); | |
121 | gettimeofday(&real, NULL); | |
122 | ||
123 | timersub(&real, &delta, &real); | |
124 | if (realout) | |
125 | *realout = real; | |
126 | return real.tv_sec; | |
127 | } | |
128 | ||
c9049b92 MS |
129 | /* Char buffer size for time-to-string api */ |
130 | #define MONOTIME_STRLEN 32 | |
131 | ||
132 | static inline char *time_to_string(time_t ts, char *buf) | |
87454e6b CS |
133 | { |
134 | struct timeval tv; | |
135 | time_t tbuf; | |
136 | ||
137 | monotime(&tv); | |
138 | tbuf = time(NULL) - (tv.tv_sec - ts); | |
139 | ||
c9049b92 | 140 | return ctime_r(&tbuf, buf); |
87454e6b CS |
141 | } |
142 | ||
d0636ead MS |
143 | /* Convert interval to human-friendly string, used in cli output e.g. */ |
144 | static inline const char *frrtime_to_interval(time_t t, char *buf, | |
145 | size_t buflen) | |
146 | { | |
147 | struct tm tm; | |
148 | ||
149 | gmtime_r(&t, &tm); | |
150 | ||
151 | if (t < ONE_DAY_SECOND) | |
152 | snprintf(buf, buflen, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, | |
153 | tm.tm_sec); | |
154 | else if (t < ONE_WEEK_SECOND) | |
155 | snprintf(buf, buflen, "%dd%02dh%02dm", tm.tm_yday, tm.tm_hour, | |
156 | tm.tm_min); | |
157 | else | |
158 | snprintf(buf, buflen, "%02dw%dd%02dh", tm.tm_yday / 7, | |
159 | tm.tm_yday - ((tm.tm_yday / 7) * 7), tm.tm_hour); | |
160 | return buf; | |
161 | } | |
162 | ||
2c76ba43 DL |
163 | enum { |
164 | /* n/a - input was seconds precision, don't print any fractional */ | |
165 | TIMEFMT_SECONDS = (1 << 0), | |
166 | /* caller is directly invoking printfrr_time and has pre-specified | |
167 | * I/Iu/Is/M/Mu/Ms/R/Ru/Rs (for printing timers) | |
168 | */ | |
169 | TIMEFMT_PRESELECT = (1 << 1), | |
170 | /* don't print any output - this is needed for invoking printfrr_time | |
171 | * from another printfrr extensions to skip over flag characters | |
172 | */ | |
173 | TIMEFMT_SKIP = (1 << 2), | |
174 | /* use spaces in appropriate places */ | |
175 | TIMEFMT_SPACE = (1 << 3), | |
176 | ||
177 | /* input interpretations: */ | |
178 | TIMEFMT_REALTIME = (1 << 8), | |
179 | TIMEFMT_MONOTONIC = (1 << 9), | |
180 | TIMEFMT_SINCE = (1 << 10), | |
181 | TIMEFMT_UNTIL = (1 << 11), | |
182 | ||
183 | TIMEFMT_ABSOLUTE = TIMEFMT_REALTIME | TIMEFMT_MONOTONIC, | |
184 | TIMEFMT_ANCHORS = TIMEFMT_SINCE | TIMEFMT_UNTIL, | |
185 | ||
186 | /* calendaric formats: */ | |
187 | TIMEFMT_ISO8601 = (1 << 16), | |
188 | ||
189 | /* interval formats: */ | |
190 | /* 't' - use [t]raditional 3-block format */ | |
191 | TIMEFMT_BASIC = (1 << 24), | |
192 | /* 'm' - select mm:ss */ | |
193 | TIMEFMT_MMSS = (1 << 25), | |
194 | /* 'h' - select hh:mm:ss */ | |
195 | TIMEFMT_HHMMSS = (1 << 26), | |
196 | /* 'd' - print as decimal number of seconds */ | |
197 | TIMEFMT_DECIMAL = (1 << 27), | |
198 | /* 'mx'/'hx' - replace zero value with "--:--" or "--:--:--" */ | |
199 | TIMEFMT_DASHES = (1 << 31), | |
200 | ||
201 | /* helpers for reference */ | |
202 | TIMEFMT_TIMER_DEADLINE = | |
203 | TIMEFMT_PRESELECT | TIMEFMT_MONOTONIC | TIMEFMT_UNTIL, | |
204 | TIMEFMT_TIMER_INTERVAL = TIMEFMT_PRESELECT, | |
205 | }; | |
206 | ||
207 | extern ssize_t printfrr_time(struct fbuf *buf, struct printfrr_eargs *ea, | |
208 | const struct timespec *ts, unsigned int flags); | |
209 | ||
5e244469 RW |
210 | #ifdef __cplusplus |
211 | } | |
212 | #endif | |
213 | ||
7790a2d6 | 214 | #endif /* _FRR_MONOTIME_H */ |