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