Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/include/timevalops.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * timevalops.h -- calculations on 'struct timeval' values
3
 *
4
 * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
5
 * The contents of 'html/copyright.html' apply.
6
 *
7
 * For a rationale look at 'timespecops.h'; we do the same here, but the
8
 * normalisation keeps the microseconds in [0 .. 10^6[, of course.
9
 */
10
#ifndef TIMEVALOPS_H
11
#define TIMEVALOPS_H
12
13
#include <sys/types.h>
14
#include <stdio.h>
15
16
#include "ntp.h"
17
#include "timetoa.h"
18
19
20
/* microseconds per second */
21
#define MICROSECONDS 1000000
22
23
#ifndef HAVE_U_INT64
24
# define USE_TSF_USEC_TABLES
25
#endif
26
27
/*
28
 * Convert usec to a time stamp fraction.
29
 */
30
#ifdef USE_TSF_USEC_TABLES
31
extern const u_int32 ustotslo[];
32
extern const u_int32 ustotsmid[];
33
extern const u_int32 ustotshi[];
34
35
# define TVUTOTSF(tvu, tsf)           \
36
   ((tsf) = ustotslo[(tvu) & 0xff]        \
37
      + ustotsmid[((tvu) >> 8) & 0xff]      \
38
      + ustotshi[((tvu) >> 16) & 0xf])
39
#else
40
# define TVUTOTSF(tvu, tsf)           \
41
  ((tsf) = (u_int32)            \
42
     ((((u_int64)(tvu) << 32) + MICROSECONDS / 2) /   \
43
      MICROSECONDS))
44
#endif
45
46
/*
47
 * Convert a time stamp fraction to microseconds.  The time stamp
48
 * fraction is assumed to be unsigned.
49
 */
50
#ifdef USE_TSF_USEC_TABLES
51
extern const u_int32 tstouslo[256];
52
extern const u_int32 tstousmid[256];
53
extern const u_int32 tstoushi[128];
54
55
/*
56
 * TV_SHIFT is used to turn the table result into a usec value.  To
57
 * round, add in TV_ROUNDBIT before shifting.
58
 */
59
#define TV_SHIFT  3
60
#define TV_ROUNDBIT 0x4
61
62
# define TSFTOTVU(tsf, tvu)           \
63
   ((tvu) = (tstoushi[((tsf) >> 24) & 0xff]     \
64
      + tstousmid[((tsf) >> 16) & 0xff]     \
65
      + tstouslo[((tsf) >> 9) & 0x7f]     \
66
      + TV_ROUNDBIT) >> TV_SHIFT)
67
#else
68
# define TSFTOTVU(tsf, tvu)           \
69
   ((tvu) = (int32)           \
70
      (((u_int64)(tsf) * MICROSECONDS + 0x80000000) >> 32))
71
#endif
72
73
/*
74
 * Convert a struct timeval to a time stamp.
75
 */
76
#define TVTOTS(tv, ts) \
77
  do { \
78
    (ts)->l_ui = (u_long)(tv)->tv_sec; \
79
    TVUTOTSF((tv)->tv_usec, (ts)->l_uf); \
80
  } while (FALSE)
81
82
#define sTVTOTS(tv, ts) \
83
  do { \
84
    int isneg = 0; \
85
    long usec; \
86
    (ts)->l_ui = (tv)->tv_sec; \
87
    usec = (tv)->tv_usec; \
88
    if (((tv)->tv_sec < 0) || ((tv)->tv_usec < 0)) { \
89
      usec = -usec; \
90
      (ts)->l_ui = -(ts)->l_ui; \
91
      isneg = 1; \
92
    } \
93
    TVUTOTSF(usec, (ts)->l_uf); \
94
    if (isneg) { \
95
      L_NEG((ts)); \
96
    } \
97
  } while (FALSE)
98
99
/*
100
 * Convert a time stamp to a struct timeval.  The time stamp
101
 * has to be positive.
102
 */
103
#define TSTOTV(ts, tv) \
104
  do { \
105
    (tv)->tv_sec = (ts)->l_ui; \
106
    TSFTOTVU((ts)->l_uf, (tv)->tv_usec); \
107
    if ((tv)->tv_usec == 1000000) { \
108
      (tv)->tv_sec++; \
109
      (tv)->tv_usec = 0; \
110
    } \
111
  } while (FALSE)
112
113
114
/*
115
 * predicate: returns TRUE if the microseconds are in nominal range
116
 * use like: int timeval_isnormal(const struct timeval *x)
117
 */
118
#define timeval_isnormal(x) \
119
  ((x)->tv_usec >= 0 && (x)->tv_usec < MICROSECONDS)
120
121
/*
122
 * Convert milliseconds to a time stamp fraction.  Unused except for
123
 * refclock_leitch.c, so accompanying lookup tables were removed in
124
 * favor of reusing the microseconds conversion tables.
125
 */
126
#define MSUTOTSF(msu, tsf)  TVUTOTSF((msu) * 1000, tsf)
127
128
/*
129
 * predicate: returns TRUE if the microseconds are out-of-bounds
130
 * use like: int timeval_isdenormal(const struct timeval *x)
131
 */
132
#define timeval_isdenormal(x) (!timeval_isnormal(x))
133
134
/* make sure microseconds are in nominal range */
135
static inline struct timeval
136
normalize_tval(
137
  struct timeval  x
138
  )
139
0
{
140
0
  long    z;
141
0
142
0
  /*
143
0
   * If the fraction becomes excessive denormal, we use division
144
0
   * to do first partial normalisation. The normalisation loops
145
0
   * following will do the remaining cleanup. Since the size of
146
0
   * tv_usec has a peculiar definition by the standard the range
147
0
   * check is coded manually. And labs() is intentionally not used
148
0
   * here: it has implementation-defined behaviour when applied
149
0
   * to LONG_MIN.
150
0
   */
151
0
  if (x.tv_usec < -3l * MICROSECONDS ||
152
0
      x.tv_usec >  3l * MICROSECONDS  ) {
153
0
    z = x.tv_usec / MICROSECONDS;
154
0
    x.tv_usec -= z * MICROSECONDS;
155
0
    x.tv_sec += z;
156
0
  }
157
0
158
0
  /*
159
0
   * Do any remaining normalisation steps in loops. This takes 3
160
0
   * steps max, and should outperform a division even if the
161
0
   * mul-by-inverse trick is employed. (It also does the floor
162
0
   * division adjustment if the above division was executed.)
163
0
   */
164
0
  if (x.tv_usec < 0)
165
0
    do {
166
0
      x.tv_usec += MICROSECONDS;
167
0
      x.tv_sec--;
168
0
    } while (x.tv_usec < 0);
169
0
  else if (x.tv_usec >= MICROSECONDS)
170
0
    do {
171
0
      x.tv_usec -= MICROSECONDS;
172
0
      x.tv_sec++;
173
0
    } while (x.tv_usec >= MICROSECONDS);
174
0
175
0
  return x;
176
0
}
177
178
/* x = a + b */
179
static inline struct timeval
180
add_tval(
181
  struct timeval  a,
182
  struct timeval  b
183
  )
184
0
{
185
0
  struct timeval  x;
186
0
187
0
  x = a;
188
0
  x.tv_sec += b.tv_sec;
189
0
  x.tv_usec += b.tv_usec;
190
0
191
0
  return normalize_tval(x);
192
0
}
193
194
/* x = a + b, b is fraction only */
195
static inline struct timeval
196
add_tval_us(
197
  struct timeval  a,
198
  long    b
199
  )
200
0
{
201
0
  struct timeval x;
202
0
203
0
  x = a;
204
0
  x.tv_usec += b;
205
0
206
0
  return normalize_tval(x);
207
0
}
208
209
/* x = a - b */
210
static inline struct timeval
211
sub_tval(
212
  struct timeval  a,
213
  struct timeval  b
214
  )
215
0
{ 
216
0
  struct timeval  x;
217
0
218
0
  x = a;
219
0
  x.tv_sec -= b.tv_sec;
220
0
  x.tv_usec -= b.tv_usec;
221
0
222
0
  return normalize_tval(x);
223
0
}
224
225
/* x = a - b, b is fraction only */
226
static inline struct timeval
227
sub_tval_us(
228
  struct timeval  a,
229
  long    b
230
  )
231
0
{
232
0
  struct timeval x;
233
0
234
0
  x = a;
235
0
  x.tv_usec -= b;
236
0
237
0
  return normalize_tval(x);
238
0
}
239
240
/* x = -a */
241
static inline struct timeval
242
neg_tval(
243
  struct timeval  a
244
  )
245
0
{ 
246
0
  struct timeval  x;
247
0
248
0
  x.tv_sec = -a.tv_sec;
249
0
  x.tv_usec = -a.tv_usec;
250
0
251
0
  return normalize_tval(x);
252
0
}
253
254
/* x = abs(a) */
255
static inline struct timeval
256
abs_tval(
257
  struct timeval  a
258
  )
259
0
{
260
0
  struct timeval  c;
261
0
262
0
  c = normalize_tval(a);
263
0
  if (c.tv_sec < 0) {
264
0
    if (c.tv_usec != 0) {
265
0
      c.tv_sec = -c.tv_sec - 1;
266
0
      c.tv_usec = MICROSECONDS - c.tv_usec;
267
0
    } else {
268
0
      c.tv_sec = -c.tv_sec;
269
0
    }
270
0
  }
271
0
272
0
  return c;
273
0
}
274
275
/*
276
 * compare previously-normalised a and b
277
 * return 1 / 0 / -1 if a < / == / > b
278
 */
279
static inline int
280
cmp_tval(
281
  struct timeval a,
282
  struct timeval b
283
  )
284
0
{
285
0
  int r;
286
0
287
0
  r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
288
0
  if (0 == r)
289
0
    r = (a.tv_usec > b.tv_usec) -
290
0
        (a.tv_usec < b.tv_usec);
291
0
  
292
0
  return r;
293
0
}
294
295
/*
296
 * compare possibly-denormal a and b
297
 * return 1 / 0 / -1 if a < / == / > b
298
 */
299
static inline int
300
cmp_tval_denorm(
301
  struct timeval  a,
302
  struct timeval  b
303
  )
304
0
{
305
0
  return cmp_tval(normalize_tval(a), normalize_tval(b));
306
0
}
307
308
/*
309
 * test previously-normalised a
310
 * return 1 / 0 / -1 if a < / == / > 0
311
 */
312
static inline int
313
test_tval(
314
  struct timeval  a
315
  )
316
0
{
317
0
  int   r;
318
0
319
0
  r = (a.tv_sec > 0) - (a.tv_sec < 0);
320
0
  if (r == 0)
321
0
    r = (a.tv_usec > 0);
322
0
  
323
0
  return r;
324
0
}
325
326
/*
327
 * test possibly-denormal a
328
 * return 1 / 0 / -1 if a < / == / > 0
329
 */
330
static inline int
331
test_tval_denorm(
332
  struct timeval  a
333
  )
334
0
{
335
0
  return test_tval(normalize_tval(a));
336
0
}
337
338
/* return LIB buffer ptr to string rep */
339
static inline const char *
340
tvaltoa(
341
  struct timeval  x
342
  )
343
0
{
344
0
  return format_time_fraction(x.tv_sec, x.tv_usec, 6);
345
0
}
346
347
/* convert from timeval duration to l_fp duration */
348
static inline l_fp
349
tval_intv_to_lfp(
350
  struct timeval  x
351
  )
352
0
{
353
0
  struct timeval  v;
354
0
  l_fp    y;
355
0
  
356
0
  v = normalize_tval(x);
357
0
  TVUTOTSF(v.tv_usec, y.l_uf);
358
0
  y.l_i = (int32)v.tv_sec;
359
0
360
0
  return y;
361
0
}
362
363
/* x must be UN*X epoch, output *y will be in NTP epoch */
364
static inline l_fp
365
tval_stamp_to_lfp(
366
  struct timeval  x
367
  )
368
0
{
369
0
  l_fp    y;
370
0
371
0
  y = tval_intv_to_lfp(x);
372
0
  y.l_ui += JAN_1970;
373
0
374
0
  return y;
375
0
}
376
377
/* convert to l_fp type, relative signed/unsigned and absolute */
378
static inline struct timeval
379
lfp_intv_to_tval(
380
  l_fp    x
381
  )
382
0
{
383
0
  struct timeval  out;
384
0
  l_fp    absx;
385
0
  int   neg;
386
0
  
387
0
  neg = L_ISNEG(&x);
388
0
  absx = x;
389
0
  if (neg) {
390
0
    L_NEG(&absx); 
391
0
  }
392
0
  TSFTOTVU(absx.l_uf, out.tv_usec);
393
0
  out.tv_sec = absx.l_i;
394
0
  if (neg) {
395
0
    out.tv_sec = -out.tv_sec;
396
0
    out.tv_usec = -out.tv_usec;
397
0
    out = normalize_tval(out);
398
0
  }
399
0
400
0
  return out;
401
0
}
402
403
static inline struct timeval
404
lfp_uintv_to_tval(
405
  l_fp    x
406
  )
407
0
{
408
0
  struct timeval  out;
409
0
  
410
0
  TSFTOTVU(x.l_uf, out.tv_usec);
411
0
  out.tv_sec = x.l_ui;
412
0
413
0
  return out;
414
0
}
415
416
/*
417
 * absolute (timestamp) conversion. Input is time in NTP epoch, output
418
 * is in UN*X epoch. The NTP time stamp will be expanded around the
419
 * pivot time *p or the current time, if p is NULL.
420
 */
421
static inline struct timeval
422
lfp_stamp_to_tval(
423
  l_fp    x,
424
  const time_t *  p
425
  )
426
0
{
427
0
  struct timeval  out;
428
0
  vint64    sec;
429
0
430
0
  sec = ntpcal_ntp_to_time(x.l_ui, p);
431
0
  TSFTOTVU(x.l_uf, out.tv_usec);
432
0
433
0
  /* copying a vint64 to a time_t needs some care... */
434
0
#if SIZEOF_TIME_T <= 4
435
0
  out.tv_sec = (time_t)sec.d_s.lo;
436
0
#elif defined(HAVE_INT64)
437
0
  out.tv_sec = (time_t)sec.q_s;
438
0
#else
439
0
  out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo;
440
0
#endif
441
0
  out = normalize_tval(out);
442
0
443
0
  return out;
444
0
}
445
446
#endif  /* TIMEVALOPS_H */