/*
* ntp_fp.h - definitions for NTP fixed/floating-point arithmetic
*/
#ifndef NTP_FP_H
#define NTP_FP_H
#include "ntp_types.h"
/*
* NTP uses two fixed point formats. The first (l_fp) is the "long"
* format and is 64 bits long with the decimal between bits 31 and 32.
* This is used for time stamps in the NTP packet header (in network
* byte order) and for internal computations of offsets (in local host
* byte order). We use the same structure for both signed and unsigned
* values, which is a big hack but saves rewriting all the operators
* twice. Just to confuse this, we also sometimes just carry the
* fractional part in calculations, in both signed and unsigned forms.
* Anyway, an l_fp looks like:
*
* 0 1 2 3
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Integral Part |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Fractional Part |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
typedef struct {
union {
u_int32 Xl_ui;
int32 Xl_i;
} Ul_i;
u_int32 l_uf;
} l_fp;
#define l_ui Ul_i.Xl_ui /* unsigned integral part */
#define l_i Ul_i.Xl_i /* signed integral part */
/*
* Fractional precision (of an l_fp) is actually the number of
* bits in a long.
*/
#define FRACTION_PREC (32)
/*
* The second fixed point format is 32 bits, with the decimal between
* bits 15 and 16. There is a signed version (s_fp) and an unsigned
* version (u_fp). This is used to represent synchronizing distance
* and synchronizing dispersion in the NTP packet header (again, in
* network byte order) and internally to hold both distance and
* dispersion values (in local byte order). In network byte order
* it looks like:
*
* 0 1 2 3
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Integer Part | Fraction Part |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
typedef int32 s_fp;
typedef u_int32 u_fp;
/*
* A unit second in fp format. Actually 2**(half_the_bits_in_a_long)
*/
#define FP_SECOND (0x10000)
/*
* Primitive operations on long fixed point values. If these are
* reminiscent of assembler op codes it's only because some may
* be replaced by inline assembler for particular machines someday.
* These are the (kind of inefficient) run-anywhere versions.
*/
#define M_NEG(v_i, v_f) /* v = -v */ \
do { \
(v_f) = ~(v_f) + 1u; \
(v_i) = ~(v_i) + ((v_f) == 0); \
} while (FALSE)
#define M_NEGM(r_i, r_f, a_i, a_f) /* r = -a */ \
do { \
(r_f) = ~(a_f) + 1u; \
(r_i) = ~(a_i) + ((r_f) == 0); \
} while (FALSE)
#define M_ADD(r_i, r_f, a_i, a_f) /* r += a */ \
do { \
u_int32 add_t = (r_f); \
(r_f) += (a_f); \
(r_i) += (a_i) + ((u_int32)(r_f) < add_t); \
} while (FALSE)
/*
* l_fp/double conversions
*/
#define FRAC 4294967296.0 /* 2^32 as a double */
/*
* Use 64 bit integers if available. Solaris on SPARC has a problem
* compiling parsesolaris.c if ntp_fp.h includes math.h, due to
* archaic gets() and printf() prototypes used in Solaris kernel
* headers. So far the problem has only been seen with gcc, but it
* may also affect Sun compilers, in which case the defined(__GNUC__)
* term should be removed.
* XSCALE also generates bad code for these, at least with GCC 3.3.5.
* This is unrelated to math.h, but the same solution applies.
*/
#if defined(HAVE_U_INT64) && \
!(defined(__SVR4) && defined(__sun) && \
defined(sparc) && defined(__GNUC__) || \
defined(__arm__) && defined(__XSCALE__) && defined(__GNUC__))
/*
* Optional callback from libntp step_systime() to ntpd. Optional
* because other libntp clients like ntpdate don't use it.
*/
typedef void (*time_stepped_callback)(void);
extern time_stepped_callback step_callback;
/*
* Multi-thread locking for get_systime()
*
* On most systems, get_systime() is used solely by the main ntpd
* thread, but on Windows it's also used by the dedicated I/O thread.
* The [Bug 2037] changes to get_systime() have it keep state between
* calls to ensure time moves in only one direction, which means its
* use on Windows needs to be protected against simultaneous execution
* to avoid falsely detecting Lamport violations by ensuring only one
* thread at a time is in get_systime().
*/
#ifdef SYS_WINNT
extern CRITICAL_SECTION get_systime_cs;
# define INIT_GET_SYSTIME_CRITSEC() \
InitializeCriticalSection(&get_systime_cs)
# define ENTER_GET_SYSTIME_CRITSEC() \
EnterCriticalSection(&get_systime_cs)
# define LEAVE_GET_SYSTIME_CRITSEC() \
LeaveCriticalSection(&get_systime_cs)
# define INIT_WIN_PRECISE_TIME() \
init_win_precise_time()
#else /* !SYS_WINNT follows */
# define INIT_GET_SYSTIME_CRITSEC() \
do {} while (FALSE)
# define ENTER_GET_SYSTIME_CRITSEC() \
do {} while (FALSE)
# define LEAVE_GET_SYSTIME_CRITSEC() \
do {} while (FALSE)
# define INIT_WIN_PRECISE_TIME() \
do {} while (FALSE)
#endif