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