Home | History | Annotate | Line # | Download | only in include
      1  1.5  christos /*	$NetBSD: timespecops.h,v 1.5 2020/05/25 20:47:20 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * timespecops.h -- calculations on 'struct timespec' values
      5  1.1  christos  *
      6  1.1  christos  * Written by Juergen Perlinger (perlinger (at) ntp.org) for the NTP project.
      7  1.1  christos  * The contents of 'html/copyright.html' apply.
      8  1.1  christos  *
      9  1.1  christos  * Rationale
     10  1.1  christos  * ---------
     11  1.1  christos  *
     12  1.1  christos  * Doing basic arithmetic on a 'struct timespec' is not exceedingly
     13  1.1  christos  * hard, but it requires tedious and repetitive code to keep the result
     14  1.1  christos  * normalised. We consider a timespec normalised when the nanosecond
     15  1.1  christos  * fraction is in the interval [0 .. 10^9[ ; there are multiple value
     16  1.1  christos  * pairs of seconds and nanoseconds that denote the same time interval,
     17  1.1  christos  * but the normalised representation is unique. No two different
     18  1.1  christos  * intervals can have the same normalised representation.
     19  1.1  christos  *
     20  1.1  christos  * Another topic is the representation of negative time intervals.
     21  1.1  christos  * There's more than one way to this, since both the seconds and the
     22  1.1  christos  * nanoseconds of a timespec are signed values. IMHO, the easiest way is
     23  1.1  christos  * to use a complement representation where the nanoseconds are still
     24  1.1  christos  * normalised, no matter what the sign of the seconds value. This makes
     25  1.1  christos  * normalisation easier, since the sign of the integer part is
     26  1.1  christos  * irrelevant, and it removes several sign decision cases during the
     27  1.1  christos  * calculations.
     28  1.1  christos  *
     29  1.1  christos  * As long as no signed integer overflow can occur with the nanosecond
     30  1.1  christos  * part of the operands, all operations work as expected and produce a
     31  1.1  christos  * normalised result.
     32  1.1  christos  *
     33  1.1  christos  * The exception to this are functions fix a '_fast' suffix, which do no
     34  1.1  christos  * normalisation on input data and therefore expect the input data to be
     35  1.1  christos  * normalised.
     36  1.1  christos  *
     37  1.1  christos  * Input and output operands may overlap; all input is consumed before
     38  1.1  christos  * the output is written to.
     39  1.1  christos  */
     40  1.1  christos #ifndef TIMESPECOPS_H
     41  1.1  christos #define TIMESPECOPS_H
     42  1.1  christos 
     43  1.1  christos #include <sys/types.h>
     44  1.1  christos #include <stdio.h>
     45  1.1  christos #include <math.h>
     46  1.1  christos 
     47  1.1  christos #include "ntp.h"
     48  1.1  christos #include "timetoa.h"
     49  1.1  christos 
     50  1.1  christos 
     51  1.1  christos /* nanoseconds per second */
     52  1.1  christos #define NANOSECONDS 1000000000
     53  1.1  christos 
     54  1.1  christos /* predicate: returns TRUE if the nanoseconds are in nominal range */
     55  1.1  christos #define timespec_isnormal(x) \
     56  1.1  christos 	((x)->tv_nsec >= 0 && (x)->tv_nsec < NANOSECONDS)
     57  1.1  christos 
     58  1.1  christos /* predicate: returns TRUE if the nanoseconds are out-of-bounds */
     59  1.1  christos #define timespec_isdenormal(x)	(!timespec_isnormal(x))
     60  1.1  christos 
     61  1.1  christos 
     62  1.1  christos 
     63  1.1  christos 
     64  1.1  christos /* make sure nanoseconds are in nominal range */
     65  1.5  christos extern struct timespec normalize_tspec(struct timespec x);
     66  1.1  christos 
     67  1.1  christos /* x = a + b */
     68  1.1  christos static inline struct timespec
     69  1.1  christos add_tspec(
     70  1.1  christos 	struct timespec	a,
     71  1.1  christos 	struct timespec	b
     72  1.1  christos 	)
     73  1.1  christos {
     74  1.1  christos 	struct timespec	x;
     75  1.1  christos 
     76  1.1  christos 	x = a;
     77  1.1  christos 	x.tv_sec += b.tv_sec;
     78  1.1  christos 	x.tv_nsec += b.tv_nsec;
     79  1.1  christos 
     80  1.1  christos 	return normalize_tspec(x);
     81  1.1  christos }
     82  1.1  christos 
     83  1.1  christos /* x = a + b, b is fraction only */
     84  1.1  christos static inline struct timespec
     85  1.1  christos add_tspec_ns(
     86  1.1  christos 	struct timespec	a,
     87  1.1  christos 	long		b
     88  1.1  christos 	)
     89  1.1  christos {
     90  1.1  christos 	struct timespec x;
     91  1.1  christos 
     92  1.1  christos 	x = a;
     93  1.1  christos 	x.tv_nsec += b;
     94  1.1  christos 
     95  1.1  christos 	return normalize_tspec(x);
     96  1.1  christos }
     97  1.1  christos 
     98  1.1  christos /* x = a - b */
     99  1.1  christos static inline struct timespec
    100  1.1  christos sub_tspec(
    101  1.1  christos 	struct timespec	a,
    102  1.1  christos 	struct timespec	b
    103  1.1  christos 	)
    104  1.1  christos {
    105  1.1  christos 	struct timespec x;
    106  1.1  christos 
    107  1.1  christos 	x = a;
    108  1.1  christos 	x.tv_sec -= b.tv_sec;
    109  1.1  christos 	x.tv_nsec -= b.tv_nsec;
    110  1.1  christos 
    111  1.1  christos 	return normalize_tspec(x);
    112  1.1  christos }
    113  1.1  christos 
    114  1.1  christos /* x = a - b, b is fraction only */
    115  1.1  christos static inline struct timespec
    116  1.1  christos sub_tspec_ns(
    117  1.1  christos 	struct timespec	a,
    118  1.1  christos 	long		b
    119  1.1  christos 	)
    120  1.1  christos {
    121  1.1  christos 	struct timespec	x;
    122  1.1  christos 
    123  1.1  christos 	x = a;
    124  1.1  christos 	x.tv_nsec -= b;
    125  1.1  christos 
    126  1.1  christos 	return normalize_tspec(x);
    127  1.1  christos }
    128  1.1  christos 
    129  1.1  christos /* x = -a */
    130  1.1  christos static inline struct timespec
    131  1.1  christos neg_tspec(
    132  1.1  christos 	struct timespec	a
    133  1.1  christos 	)
    134  1.1  christos {
    135  1.1  christos 	struct timespec	x;
    136  1.1  christos 
    137  1.1  christos 	x.tv_sec = -a.tv_sec;
    138  1.1  christos 	x.tv_nsec = -a.tv_nsec;
    139  1.1  christos 
    140  1.1  christos 	return normalize_tspec(x);
    141  1.1  christos }
    142  1.1  christos 
    143  1.1  christos /* x = abs(a) */
    144  1.5  christos struct timespec abs_tspec(struct timespec a);
    145  1.1  christos 
    146  1.1  christos /*
    147  1.1  christos  * compare previously-normalised a and b
    148  1.1  christos  * return 1 / 0 / -1 if a < / == / > b
    149  1.1  christos  */
    150  1.5  christos extern int cmp_tspec(struct timespec a,	struct timespec b);
    151  1.1  christos 
    152  1.1  christos /*
    153  1.1  christos  * compare possibly-denormal a and b
    154  1.1  christos  * return 1 / 0 / -1 if a < / == / > b
    155  1.1  christos  */
    156  1.1  christos static inline int
    157  1.1  christos cmp_tspec_denorm(
    158  1.1  christos 	struct timespec	a,
    159  1.1  christos 	struct timespec	b
    160  1.1  christos 	)
    161  1.1  christos {
    162  1.1  christos 	return cmp_tspec(normalize_tspec(a), normalize_tspec(b));
    163  1.1  christos }
    164  1.1  christos 
    165  1.1  christos /*
    166  1.1  christos  * test previously-normalised a
    167  1.1  christos  * return 1 / 0 / -1 if a < / == / > 0
    168  1.1  christos  */
    169  1.5  christos extern int test_tspec(struct timespec a);
    170  1.1  christos 
    171  1.1  christos /*
    172  1.1  christos  * test possibly-denormal a
    173  1.1  christos  * return 1 / 0 / -1 if a < / == / > 0
    174  1.1  christos  */
    175  1.1  christos static inline int
    176  1.1  christos test_tspec_denorm(
    177  1.1  christos 	struct timespec	a
    178  1.1  christos 	)
    179  1.1  christos {
    180  1.1  christos 	return test_tspec(normalize_tspec(a));
    181  1.1  christos }
    182  1.1  christos 
    183  1.1  christos /* return LIB buffer ptr to string rep */
    184  1.1  christos static inline const char *
    185  1.1  christos tspectoa(
    186  1.1  christos 	struct timespec	x
    187  1.1  christos 	)
    188  1.1  christos {
    189  1.1  christos 	return format_time_fraction(x.tv_sec, x.tv_nsec, 9);
    190  1.1  christos }
    191  1.1  christos 
    192  1.1  christos /*
    193  1.1  christos  *  convert to l_fp type, relative and absolute
    194  1.1  christos  */
    195  1.1  christos 
    196  1.1  christos /* convert from timespec duration to l_fp duration */
    197  1.5  christos extern l_fp tspec_intv_to_lfp(struct timespec x);
    198  1.1  christos 
    199  1.1  christos /* x must be UN*X epoch, output will be in NTP epoch */
    200  1.1  christos static inline l_fp
    201  1.1  christos tspec_stamp_to_lfp(
    202  1.1  christos 	struct timespec	x
    203  1.1  christos 	)
    204  1.1  christos {
    205  1.1  christos 	l_fp		y;
    206  1.1  christos 
    207  1.1  christos 	y = tspec_intv_to_lfp(x);
    208  1.1  christos 	y.l_ui += JAN_1970;
    209  1.1  christos 
    210  1.1  christos 	return y;
    211  1.1  christos }
    212  1.1  christos 
    213  1.1  christos /* convert from l_fp type, relative signed/unsigned and absolute */
    214  1.5  christos extern struct timespec lfp_intv_to_tspec(l_fp x);
    215  1.5  christos extern struct timespec lfp_uintv_to_tspec(l_fp x);
    216  1.1  christos 
    217  1.1  christos /*
    218  1.1  christos  * absolute (timestamp) conversion. Input is time in NTP epoch, output
    219  1.1  christos  * is in UN*X epoch. The NTP time stamp will be expanded around the
    220  1.1  christos  * pivot time *p or the current time, if p is NULL.
    221  1.1  christos  */
    222  1.5  christos extern struct timespec lfp_stamp_to_tspec(l_fp x, const time_t *pivot);
    223  1.1  christos 
    224  1.1  christos #endif	/* TIMESPECOPS_H */
    225