154359Sroberto/* 254359Sroberto * ntp_fp.h - definitions for NTP fixed/floating-point arithmetic 354359Sroberto */ 454359Sroberto 554359Sroberto#ifndef NTP_FP_H 654359Sroberto#define NTP_FP_H 754359Sroberto 854359Sroberto#include "ntp_types.h" 954359Sroberto 1054359Sroberto/* 1154359Sroberto * NTP uses two fixed point formats. The first (l_fp) is the "long" 1254359Sroberto * format and is 64 bits long with the decimal between bits 31 and 32. 1354359Sroberto * This is used for time stamps in the NTP packet header (in network 1454359Sroberto * byte order) and for internal computations of offsets (in local host 1554359Sroberto * byte order). We use the same structure for both signed and unsigned 1654359Sroberto * values, which is a big hack but saves rewriting all the operators 1754359Sroberto * twice. Just to confuse this, we also sometimes just carry the 1854359Sroberto * fractional part in calculations, in both signed and unsigned forms. 1954359Sroberto * Anyway, an l_fp looks like: 2054359Sroberto * 2154359Sroberto * 0 1 2 3 2254359Sroberto * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2354359Sroberto * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2454359Sroberto * | Integral Part | 2554359Sroberto * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2654359Sroberto * | Fractional Part | 2754359Sroberto * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2854359Sroberto * 2954359Sroberto */ 3054359Srobertotypedef struct { 3154359Sroberto union { 3254359Sroberto u_int32 Xl_ui; 3354359Sroberto int32 Xl_i; 3454359Sroberto } Ul_i; 35290001Sglebius u_int32 l_uf; 3654359Sroberto} l_fp; 3754359Sroberto 3854359Sroberto#define l_ui Ul_i.Xl_ui /* unsigned integral part */ 3954359Sroberto#define l_i Ul_i.Xl_i /* signed integral part */ 4054359Sroberto 4154359Sroberto/* 4254359Sroberto * Fractional precision (of an l_fp) is actually the number of 4354359Sroberto * bits in a long. 4454359Sroberto */ 4554359Sroberto#define FRACTION_PREC (32) 4654359Sroberto 4754359Sroberto 4854359Sroberto/* 4954359Sroberto * The second fixed point format is 32 bits, with the decimal between 5054359Sroberto * bits 15 and 16. There is a signed version (s_fp) and an unsigned 5154359Sroberto * version (u_fp). This is used to represent synchronizing distance 5254359Sroberto * and synchronizing dispersion in the NTP packet header (again, in 5354359Sroberto * network byte order) and internally to hold both distance and 5454359Sroberto * dispersion values (in local byte order). In network byte order 5554359Sroberto * it looks like: 5654359Sroberto * 5754359Sroberto * 0 1 2 3 5854359Sroberto * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 5954359Sroberto * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6054359Sroberto * | Integer Part | Fraction Part | 6154359Sroberto * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6254359Sroberto * 6354359Sroberto */ 6454359Srobertotypedef int32 s_fp; 6554359Srobertotypedef u_int32 u_fp; 6654359Sroberto 6754359Sroberto/* 68290001Sglebius * A unit second in fp format. Actually 2**(half_the_bits_in_a_long) 6954359Sroberto */ 7054359Sroberto#define FP_SECOND (0x10000) 7154359Sroberto 7254359Sroberto/* 7354359Sroberto * Byte order conversions 7454359Sroberto */ 7554359Sroberto#define HTONS_FP(x) (htonl(x)) 7654359Sroberto#define NTOHS_FP(x) (ntohl(x)) 7754359Sroberto 78290001Sglebius#define NTOHL_MFP(ni, nf, hi, hf) \ 79290001Sglebius do { \ 80290001Sglebius (hi) = ntohl(ni); \ 81290001Sglebius (hf) = ntohl(nf); \ 82290001Sglebius } while (FALSE) 8354359Sroberto 84290001Sglebius#define HTONL_MFP(hi, hf, ni, nf) \ 85290001Sglebius do { \ 86290001Sglebius (ni) = htonl(hi); \ 87290001Sglebius (nf) = htonl(hf); \ 88290001Sglebius } while (FALSE) 89290001Sglebius 90290001Sglebius#define HTONL_FP(h, n) \ 91290001Sglebius HTONL_MFP((h)->l_ui, (h)->l_uf, (n)->l_ui, (n)->l_uf) 92290001Sglebius 93290001Sglebius#define NTOHL_FP(n, h) \ 94290001Sglebius NTOHL_MFP((n)->l_ui, (n)->l_uf, (h)->l_ui, (h)->l_uf) 95290001Sglebius 96290001Sglebius/* Convert unsigned ts fraction to net order ts */ 97290001Sglebius#define HTONL_UF(uf, nts) \ 98290001Sglebius do { \ 99290001Sglebius (nts)->l_ui = 0; \ 100290001Sglebius (nts)->l_uf = htonl(uf); \ 101290001Sglebius } while (FALSE) 102290001Sglebius 10354359Sroberto/* 10454359Sroberto * Conversions between the two fixed point types 10554359Sroberto */ 10654359Sroberto#define MFPTOFP(x_i, x_f) (((x_i) >= 0x00010000) ? 0x7fffffff : \ 10754359Sroberto (((x_i) <= -0x00010000) ? 0x80000000 : \ 10854359Sroberto (((x_i)<<16) | (((x_f)>>16)&0xffff)))) 109290001Sglebius#define LFPTOFP(v) MFPTOFP((v)->l_i, (v)->l_uf) 11054359Sroberto 11154359Sroberto#define UFPTOLFP(x, v) ((v)->l_ui = (u_fp)(x)>>16, (v)->l_uf = (x)<<16) 11254359Sroberto#define FPTOLFP(x, v) (UFPTOLFP((x), (v)), (x) < 0 ? (v)->l_ui -= 0x10000 : 0) 11354359Sroberto 114290001Sglebius#define MAXLFP(v) ((v)->l_ui = 0x7fffffffu, (v)->l_uf = 0xffffffffu) 115290001Sglebius#define MINLFP(v) ((v)->l_ui = 0x80000000u, (v)->l_uf = 0u) 11654359Sroberto 11754359Sroberto/* 11854359Sroberto * Primitive operations on long fixed point values. If these are 11954359Sroberto * reminiscent of assembler op codes it's only because some may 12054359Sroberto * be replaced by inline assembler for particular machines someday. 12154359Sroberto * These are the (kind of inefficient) run-anywhere versions. 12254359Sroberto */ 123290001Sglebius#define M_NEG(v_i, v_f) /* v = -v */ \ 12454359Sroberto do { \ 125290001Sglebius (v_f) = ~(v_f) + 1u; \ 126290001Sglebius (v_i) = ~(v_i) + ((v_f) == 0); \ 127290001Sglebius } while (FALSE) 12854359Sroberto 129290001Sglebius#define M_NEGM(r_i, r_f, a_i, a_f) /* r = -a */ \ 13054359Sroberto do { \ 131290001Sglebius (r_f) = ~(a_f) + 1u; \ 132290001Sglebius (r_i) = ~(a_i) + ((r_f) == 0); \ 133290001Sglebius } while (FALSE) 13454359Sroberto 135290001Sglebius#define M_ADD(r_i, r_f, a_i, a_f) /* r += a */ \ 13654359Sroberto do { \ 137290001Sglebius u_int32 add_t = (r_f); \ 138290001Sglebius (r_f) += (a_f); \ 139290001Sglebius (r_i) += (a_i) + ((u_int32)(r_f) < add_t); \ 140290001Sglebius } while (FALSE) 14154359Sroberto 142290001Sglebius#define M_ADD3(r_o, r_i, r_f, a_o, a_i, a_f) /* r += a, three word */ \ 14354359Sroberto do { \ 144290001Sglebius u_int32 add_t, add_c; \ 145290001Sglebius add_t = (r_f); \ 146290001Sglebius (r_f) += (a_f); \ 147290001Sglebius add_c = ((u_int32)(r_f) < add_t); \ 148290001Sglebius (r_i) += add_c; \ 149290001Sglebius add_c = ((u_int32)(r_i) < add_c); \ 150290001Sglebius add_t = (r_i); \ 151290001Sglebius (r_i) += (a_i); \ 152290001Sglebius add_c |= ((u_int32)(r_i) < add_t); \ 153290001Sglebius (r_o) += (a_o) + add_c; \ 154290001Sglebius } while (FALSE) 15554359Sroberto 15654359Sroberto#define M_SUB(r_i, r_f, a_i, a_f) /* r -= a */ \ 15754359Sroberto do { \ 158290001Sglebius u_int32 sub_t = (r_f); \ 159290001Sglebius (r_f) -= (a_f); \ 160290001Sglebius (r_i) -= (a_i) + ((u_int32)(r_f) > sub_t); \ 161290001Sglebius } while (FALSE) 16254359Sroberto 16354359Sroberto#define M_RSHIFTU(v_i, v_f) /* v >>= 1, v is unsigned */ \ 16454359Sroberto do { \ 165290001Sglebius (v_f) = ((u_int32)(v_f) >> 1) | ((u_int32)(v_i) << 31); \ 166290001Sglebius (v_i) = ((u_int32)(v_i) >> 1); \ 167290001Sglebius } while (FALSE) 16854359Sroberto 16954359Sroberto#define M_RSHIFT(v_i, v_f) /* v >>= 1, v is signed */ \ 17054359Sroberto do { \ 171290001Sglebius (v_f) = ((u_int32)(v_f) >> 1) | ((u_int32)(v_i) << 31); \ 172290001Sglebius (v_i) = ((u_int32)(v_i) >> 1) | ((u_int32)(v_i) & 0x80000000); \ 173290001Sglebius } while (FALSE) 17454359Sroberto 17554359Sroberto#define M_LSHIFT(v_i, v_f) /* v <<= 1 */ \ 17654359Sroberto do { \ 177290001Sglebius (v_i) = ((u_int32)(v_i) << 1) | ((u_int32)(v_f) >> 31); \ 178290001Sglebius (v_f) = ((u_int32)(v_f) << 1); \ 179290001Sglebius } while (FALSE) 18054359Sroberto 181290001Sglebius#define M_LSHIFT3(v_o, v_i, v_f) /* v <<= 1, with overflow */ \ 18254359Sroberto do { \ 183290001Sglebius (v_o) = ((u_int32)(v_o) << 1) | ((u_int32)(v_i) >> 31); \ 184290001Sglebius (v_i) = ((u_int32)(v_i) << 1) | ((u_int32)(v_f) >> 31); \ 185290001Sglebius (v_f) = ((u_int32)(v_f) << 1); \ 186290001Sglebius } while (FALSE) 18754359Sroberto 188290001Sglebius#define M_ADDUF(r_i, r_f, uf) /* r += uf, uf is u_int32 fraction */ \ 18954359Sroberto M_ADD((r_i), (r_f), 0, (uf)) /* let optimizer worry about it */ 19054359Sroberto 19154359Sroberto#define M_SUBUF(r_i, r_f, uf) /* r -= uf, uf is u_int32 fraction */ \ 19254359Sroberto M_SUB((r_i), (r_f), 0, (uf)) /* let optimizer worry about it */ 19354359Sroberto 19454359Sroberto#define M_ADDF(r_i, r_f, f) /* r += f, f is a int32 fraction */ \ 19554359Sroberto do { \ 196290001Sglebius int32 add_f = (int32)(f); \ 197290001Sglebius if (add_f >= 0) \ 198290001Sglebius M_ADD((r_i), (r_f), 0, (uint32)( add_f)); \ 199290001Sglebius else \ 200290001Sglebius M_SUB((r_i), (r_f), 0, (uint32)(-add_f)); \ 20154359Sroberto } while(0) 20254359Sroberto 203290001Sglebius#define M_ISNEG(v_i) /* v < 0 */ \ 20454359Sroberto (((v_i) & 0x80000000) != 0) 20554359Sroberto 206290001Sglebius#define M_ISGT(a_i, a_f, b_i, b_f) /* a > b signed */ \ 207290001Sglebius (((u_int32)((a_i) ^ 0x80000000) > (u_int32)((b_i) ^ 0x80000000)) || \ 208290001Sglebius ((a_i) == (b_i) && ((u_int32)(a_f)) > ((u_int32)(b_f)))) 209290001Sglebius 210290001Sglebius#define M_ISGTU(a_i, a_f, b_i, b_f) /* a > b unsigned */ \ 211290001Sglebius (((u_int32)(a_i)) > ((u_int32)(b_i)) || \ 212290001Sglebius ((a_i) == (b_i) && ((u_int32)(a_f)) > ((u_int32)(b_f)))) 213290001Sglebius 21454359Sroberto#define M_ISHIS(a_i, a_f, b_i, b_f) /* a >= b unsigned */ \ 21554359Sroberto (((u_int32)(a_i)) > ((u_int32)(b_i)) || \ 21654359Sroberto ((a_i) == (b_i) && ((u_int32)(a_f)) >= ((u_int32)(b_f)))) 21754359Sroberto 21854359Sroberto#define M_ISGEQ(a_i, a_f, b_i, b_f) /* a >= b signed */ \ 219290001Sglebius (((u_int32)((a_i) ^ 0x80000000) > (u_int32)((b_i) ^ 0x80000000)) || \ 220290001Sglebius ((a_i) == (b_i) && (u_int32)(a_f) >= (u_int32)(b_f))) 22154359Sroberto 22254359Sroberto#define M_ISEQU(a_i, a_f, b_i, b_f) /* a == b unsigned */ \ 223290001Sglebius ((u_int32)(a_i) == (u_int32)(b_i) && (u_int32)(a_f) == (u_int32)(b_f)) 22454359Sroberto 22554359Sroberto/* 22654359Sroberto * Operations on the long fp format 22754359Sroberto */ 22854359Sroberto#define L_ADD(r, a) M_ADD((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf) 22954359Sroberto#define L_SUB(r, a) M_SUB((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf) 23054359Sroberto#define L_NEG(v) M_NEG((v)->l_ui, (v)->l_uf) 23154359Sroberto#define L_ADDUF(r, uf) M_ADDUF((r)->l_ui, (r)->l_uf, (uf)) 23254359Sroberto#define L_SUBUF(r, uf) M_SUBUF((r)->l_ui, (r)->l_uf, (uf)) 23354359Sroberto#define L_ADDF(r, f) M_ADDF((r)->l_ui, (r)->l_uf, (f)) 23454359Sroberto#define L_RSHIFT(v) M_RSHIFT((v)->l_i, (v)->l_uf) 235182007Sroberto#define L_RSHIFTU(v) M_RSHIFTU((v)->l_ui, (v)->l_uf) 23654359Sroberto#define L_LSHIFT(v) M_LSHIFT((v)->l_ui, (v)->l_uf) 23754359Sroberto#define L_CLR(v) ((v)->l_ui = (v)->l_uf = 0) 23854359Sroberto 239290001Sglebius#define L_ISNEG(v) M_ISNEG((v)->l_ui) 240290001Sglebius#define L_ISZERO(v) (((v)->l_ui | (v)->l_uf) == 0) 241290001Sglebius#define L_ISGT(a, b) M_ISGT((a)->l_i, (a)->l_uf, (b)->l_i, (b)->l_uf) 242290001Sglebius#define L_ISGTU(a, b) M_ISGTU((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf) 243290001Sglebius#define L_ISHIS(a, b) M_ISHIS((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf) 244290001Sglebius#define L_ISGEQ(a, b) M_ISGEQ((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf) 24554359Sroberto#define L_ISEQU(a, b) M_ISEQU((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf) 24654359Sroberto 24754359Sroberto/* 24854359Sroberto * s_fp/double and u_fp/double conversions 24954359Sroberto */ 250290001Sglebius#define FRIC 65536.0 /* 2^16 as a double */ 25154359Sroberto#define DTOFP(r) ((s_fp)((r) * FRIC)) 25254359Sroberto#define DTOUFP(r) ((u_fp)((r) * FRIC)) 25354359Sroberto#define FPTOD(r) ((double)(r) / FRIC) 25454359Sroberto 25554359Sroberto/* 25654359Sroberto * l_fp/double conversions 25754359Sroberto */ 258290001Sglebius#define FRAC 4294967296.0 /* 2^32 as a double */ 259290001Sglebius 260290001Sglebius/* 261290001Sglebius * Use 64 bit integers if available. Solaris on SPARC has a problem 262290001Sglebius * compiling parsesolaris.c if ntp_fp.h includes math.h, due to 263290001Sglebius * archaic gets() and printf() prototypes used in Solaris kernel 264290001Sglebius * headers. So far the problem has only been seen with gcc, but it 265290001Sglebius * may also affect Sun compilers, in which case the defined(__GNUC__) 266290001Sglebius * term should be removed. 267290001Sglebius * XSCALE also generates bad code for these, at least with GCC 3.3.5. 268290001Sglebius * This is unrelated to math.h, but the same solution applies. 269290001Sglebius */ 270290001Sglebius#if defined(HAVE_U_INT64) && \ 271290001Sglebius !(defined(__SVR4) && defined(__sun) && \ 272290001Sglebius defined(sparc) && defined(__GNUC__) || \ 273290001Sglebius defined(__arm__) && defined(__XSCALE__) && defined(__GNUC__)) 274290001Sglebius 275290001Sglebius#include <math.h> /* ldexp() */ 276290001Sglebius 277290001Sglebius#define M_DTOLFP(d, r_ui, r_uf) /* double to l_fp */ \ 278290001Sglebius do { \ 279290001Sglebius double d_tmp; \ 280290001Sglebius u_int64 q_tmp; \ 281290001Sglebius int M_isneg; \ 282290001Sglebius \ 283290001Sglebius d_tmp = (d); \ 284290001Sglebius M_isneg = (d_tmp < 0.); \ 285290001Sglebius if (M_isneg) { \ 286290001Sglebius d_tmp = -d_tmp; \ 287290001Sglebius } \ 288290001Sglebius q_tmp = (u_int64)ldexp(d_tmp, 32); \ 289290001Sglebius if (M_isneg) { \ 290290001Sglebius q_tmp = ~q_tmp + 1; \ 291290001Sglebius } \ 292290001Sglebius (r_uf) = (u_int32)q_tmp; \ 293290001Sglebius (r_ui) = (u_int32)(q_tmp >> 32); \ 294290001Sglebius } while (FALSE) 295290001Sglebius 296290001Sglebius#define M_LFPTOD(r_ui, r_uf, d) /* l_fp to double */ \ 297290001Sglebius do { \ 298290001Sglebius double d_tmp; \ 299290001Sglebius u_int64 q_tmp; \ 300290001Sglebius int M_isneg; \ 301290001Sglebius \ 302290001Sglebius q_tmp = ((u_int64)(r_ui) << 32) + (r_uf); \ 303290001Sglebius M_isneg = M_ISNEG(r_ui); \ 304290001Sglebius if (M_isneg) { \ 305290001Sglebius q_tmp = ~q_tmp + 1; \ 306290001Sglebius } \ 307290001Sglebius d_tmp = ldexp((double)q_tmp, -32); \ 308290001Sglebius if (M_isneg) { \ 309290001Sglebius d_tmp = -d_tmp; \ 310290001Sglebius } \ 311290001Sglebius (d) = d_tmp; \ 312290001Sglebius } while (FALSE) 313290001Sglebius 314290001Sglebius#else /* use only 32 bit unsigned values */ 315290001Sglebius 316290001Sglebius#define M_DTOLFP(d, r_ui, r_uf) /* double to l_fp */ \ 31754359Sroberto do { \ 318290001Sglebius double d_tmp; \ 319290001Sglebius if ((d_tmp = (d)) < 0) { \ 320290001Sglebius (r_ui) = (u_int32)(-d_tmp); \ 321290001Sglebius (r_uf) = (u_int32)(-(d_tmp + (double)(r_ui)) * FRAC); \ 322290001Sglebius M_NEG((r_ui), (r_uf)); \ 32354359Sroberto } else { \ 324290001Sglebius (r_ui) = (u_int32)d_tmp; \ 325290001Sglebius (r_uf) = (u_int32)((d_tmp - (double)(r_ui)) * FRAC); \ 32654359Sroberto } \ 32754359Sroberto } while (0) 328290001Sglebius#define M_LFPTOD(r_ui, r_uf, d) /* l_fp to double */ \ 32954359Sroberto do { \ 330290001Sglebius u_int32 l_thi, l_tlo; \ 331290001Sglebius l_thi = (r_ui); l_tlo = (r_uf); \ 332290001Sglebius if (M_ISNEG(l_thi)) { \ 333290001Sglebius M_NEG(l_thi, l_tlo); \ 334290001Sglebius (d) = -((double)l_thi + (double)l_tlo / FRAC); \ 33554359Sroberto } else { \ 336290001Sglebius (d) = (double)l_thi + (double)l_tlo / FRAC; \ 33754359Sroberto } \ 33854359Sroberto } while (0) 339290001Sglebius#endif 340290001Sglebius 34154359Sroberto#define DTOLFP(d, v) M_DTOLFP((d), (v)->l_ui, (v)->l_uf) 34254359Sroberto#define LFPTOD(v, d) M_LFPTOD((v)->l_ui, (v)->l_uf, (d)) 34354359Sroberto 34454359Sroberto/* 34554359Sroberto * Prototypes 34654359Sroberto */ 347290001Sglebiusextern char * dofptoa (u_fp, int, short, int); 348290001Sglebiusextern char * dolfptoa (u_int32, u_int32, int, short, int); 34954359Sroberto 350290001Sglebiusextern int atolfp (const char *, l_fp *); 351290001Sglebiusextern int buftvtots (const char *, l_fp *); 352290001Sglebiusextern char * fptoa (s_fp, short); 353290001Sglebiusextern char * fptoms (s_fp, short); 354290001Sglebiusextern int hextolfp (const char *, l_fp *); 355290001Sglebiusextern void gpstolfp (int, int, unsigned long, l_fp *); 356290001Sglebiusextern int mstolfp (const char *, l_fp *); 357290001Sglebiusextern char * prettydate (l_fp *); 358290001Sglebiusextern char * gmprettydate (l_fp *); 359290001Sglebiusextern char * uglydate (l_fp *); 360290001Sglebiusextern void mfp_mul (int32 *, u_int32 *, int32, u_int32, int32, u_int32); 36154359Sroberto 362290001Sglebiusextern void set_sys_fuzz (double); 363290001Sglebiusextern void init_systime (void); 364290001Sglebiusextern void get_systime (l_fp *); 365290001Sglebiusextern int step_systime (double); 366290001Sglebiusextern int adj_systime (double); 36754359Sroberto 368290001Sglebiusextern struct tm * ntp2unix_tm (u_int32 ntp, int local); 369182007Sroberto 370290001Sglebius#define lfptoa(fpv, ndec) mfptoa((fpv)->l_ui, (fpv)->l_uf, (ndec)) 371290001Sglebius#define lfptoms(fpv, ndec) mfptoms((fpv)->l_ui, (fpv)->l_uf, (ndec)) 37254359Sroberto 373290001Sglebius#define stoa(addr) socktoa(addr) 374290001Sglebius#define ntoa(addr) stoa(addr) 375290001Sglebius#define sptoa(addr) sockporttoa(addr) 376290001Sglebius#define stohost(addr) socktohost(addr) 37754359Sroberto 378290001Sglebius#define ufptoa(fpv, ndec) dofptoa((fpv), 0, (ndec), 0) 379290001Sglebius#define ufptoms(fpv, ndec) dofptoa((fpv), 0, (ndec), 1) 380290001Sglebius#define ulfptoa(fpv, ndec) dolfptoa((fpv)->l_ui, (fpv)->l_uf, 0, (ndec), 0) 381290001Sglebius#define ulfptoms(fpv, ndec) dolfptoa((fpv)->l_ui, (fpv)->l_uf, 0, (ndec), 1) 382290001Sglebius#define umfptoa(fpi, fpf, ndec) dolfptoa((fpi), (fpf), 0, (ndec), 0) 383132451Sroberto 384290001Sglebius/* 385290001Sglebius * Optional callback from libntp step_systime() to ntpd. Optional 386290001Sglebius* because other libntp clients like ntpdate don't use it. 387290001Sglebius */ 388290001Sglebiustypedef void (*time_stepped_callback)(void); 389290001Sglebiusextern time_stepped_callback step_callback; 39054359Sroberto 391290001Sglebius/* 392290001Sglebius * Multi-thread locking for get_systime() 393290001Sglebius * 394290001Sglebius * On most systems, get_systime() is used solely by the main ntpd 395290001Sglebius * thread, but on Windows it's also used by the dedicated I/O thread. 396290001Sglebius * The [Bug 2037] changes to get_systime() have it keep state between 397290001Sglebius * calls to ensure time moves in only one direction, which means its 398290001Sglebius * use on Windows needs to be protected against simultaneous execution 399290001Sglebius * to avoid falsely detecting Lamport violations by ensuring only one 400290001Sglebius * thread at a time is in get_systime(). 401290001Sglebius */ 402290001Sglebius#ifdef SYS_WINNT 403290001Sglebiusextern CRITICAL_SECTION get_systime_cs; 404290001Sglebius# define INIT_GET_SYSTIME_CRITSEC() \ 405290001Sglebius InitializeCriticalSection(&get_systime_cs) 406290001Sglebius# define ENTER_GET_SYSTIME_CRITSEC() \ 407290001Sglebius EnterCriticalSection(&get_systime_cs) 408290001Sglebius# define LEAVE_GET_SYSTIME_CRITSEC() \ 409290001Sglebius LeaveCriticalSection(&get_systime_cs) 410290001Sglebius# define INIT_WIN_PRECISE_TIME() \ 411290001Sglebius init_win_precise_time() 412290001Sglebius#else /* !SYS_WINNT follows */ 413290001Sglebius# define INIT_GET_SYSTIME_CRITSEC() \ 414290001Sglebius do {} while (FALSE) 415290001Sglebius# define ENTER_GET_SYSTIME_CRITSEC() \ 416290001Sglebius do {} while (FALSE) 417290001Sglebius# define LEAVE_GET_SYSTIME_CRITSEC() \ 418290001Sglebius do {} while (FALSE) 419290001Sglebius# define INIT_WIN_PRECISE_TIME() \ 420290001Sglebius do {} while (FALSE) 421290001Sglebius#endif 422290001Sglebius 42354359Sroberto#endif /* NTP_FP_H */ 424