timespec.h 4.25 KB
Newer Older
1 2
/* timespec -- System time interface

Paul Eggert's avatar
Paul Eggert committed
3
   Copyright (C) 2000, 2002, 2004-2005, 2007, 2009-2019 Free Software
4 5 6 7 8 9 10 11 12 13 14 15 16
   Foundation, Inc.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
Paul Eggert's avatar
Paul Eggert committed
17
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
18 19

#if ! defined TIMESPEC_H
20
#define TIMESPEC_H
21

22
#include <time.h>
23

Paul Eggert's avatar
Paul Eggert committed
24 25 26
#ifndef _GL_INLINE_HEADER_BEGIN
 #error "Please include config.h first."
#endif
27 28 29 30 31
_GL_INLINE_HEADER_BEGIN
#ifndef _GL_TIMESPEC_INLINE
# define _GL_TIMESPEC_INLINE _GL_INLINE
#endif

Paul Eggert's avatar
Paul Eggert committed
32 33 34 35
#ifdef __cplusplus
extern "C" {
#endif

36
#include "arg-nonnull.h"
Paul Eggert's avatar
Paul Eggert committed
37 38
#include "verify.h"

Paul Eggert's avatar
Paul Eggert committed
39 40
/* Inverse resolution of timespec timestamps (in units per second),
   and log base 10 of the inverse resolution.  */
41

Paul Eggert's avatar
Paul Eggert committed
42 43 44 45 46 47 48 49
enum { TIMESPEC_HZ = 1000000000 };
enum { LOG10_TIMESPEC_HZ = 9 };

/* Obsolescent names for backward compatibility.
   They are misnomers, because TIMESPEC_RESOLUTION is not a resolution.  */

enum { TIMESPEC_RESOLUTION = TIMESPEC_HZ };
enum { LOG10_TIMESPEC_RESOLUTION = LOG10_TIMESPEC_HZ };
50 51 52 53 54 55 56 57 58 59 60 61

/* Return a timespec with seconds S and nanoseconds NS.  */

_GL_TIMESPEC_INLINE struct timespec
make_timespec (time_t s, long int ns)
{
  struct timespec r;
  r.tv_sec = s;
  r.tv_nsec = ns;
  return r;
}

62 63
/* Return negative, zero, positive if A < B, A == B, A > B, respectively.

Paul Eggert's avatar
Paul Eggert committed
64
   For each timestamp T, this code assumes that either:
65 66 67 68 69 70 71

     * T.tv_nsec is in the range 0..999999999; or
     * T.tv_sec corresponds to a valid leap second on a host that supports
       leap seconds, and T.tv_nsec is in the range 1000000000..1999999999; or
     * T.tv_sec is the minimum time_t value and T.tv_nsec is -1; or
       T.tv_sec is the maximum time_t value and T.tv_nsec is 2000000000.
       This allows for special struct timespec values that are less or
Paul Eggert's avatar
Paul Eggert committed
72
       greater than all possible valid timestamps.
73 74 75 76 77 78

   In all these cases, it is safe to subtract two tv_nsec values and
   convert the result to integer without worrying about overflow on
   any platform of interest to the GNU project, since all such
   platforms have 32-bit int or wider.

Paul Eggert's avatar
Paul Eggert committed
79
   Replacing "a.tv_nsec - b.tv_nsec" with something like
80 81 82 83 84 85
   "a.tv_nsec < b.tv_nsec ? -1 : a.tv_nsec > b.tv_nsec" would cause
   this function to work in some cases where the above assumption is
   violated, but not in all cases (e.g., a.tv_sec==1, a.tv_nsec==-2,
   b.tv_sec==0, b.tv_nsec==999999999) and is arguably not worth the
   extra instructions.  Using a subtraction has the advantage of
   detecting some invalid cases on platforms that detect integer
Paul Eggert's avatar
Paul Eggert committed
86
   overflow.  */
87

Paul Eggert's avatar
Paul Eggert committed
88
_GL_TIMESPEC_INLINE int _GL_ATTRIBUTE_PURE
89 90
timespec_cmp (struct timespec a, struct timespec b)
{
Paul Eggert's avatar
Paul Eggert committed
91 92 93 94 95 96
  if (a.tv_sec < b.tv_sec)
    return -1;
  if (a.tv_sec > b.tv_sec)
    return 1;

  /* Pacify gcc -Wstrict-overflow (bleeding-edge circa 2017-10-02).  See:
Paul Eggert's avatar
Paul Eggert committed
97
     https://lists.gnu.org/r/bug-gnulib/2017-10/msg00006.html  */
Paul Eggert's avatar
Paul Eggert committed
98 99
  assume (-1 <= a.tv_nsec && a.tv_nsec <= 2 * TIMESPEC_HZ);
  assume (-1 <= b.tv_nsec && b.tv_nsec <= 2 * TIMESPEC_HZ);
Paul Eggert's avatar
Paul Eggert committed
100 101

  return a.tv_nsec - b.tv_nsec;
102 103 104 105
}

/* Return -1, 0, 1, depending on the sign of A.  A.tv_nsec must be
   nonnegative.  */
Paul Eggert's avatar
Paul Eggert committed
106
_GL_TIMESPEC_INLINE int _GL_ATTRIBUTE_PURE
107 108 109 110 111
timespec_sign (struct timespec a)
{
  return a.tv_sec < 0 ? -1 : a.tv_sec || a.tv_nsec;
}

Paul Eggert's avatar
Paul Eggert committed
112 113 114 115 116 117
struct timespec timespec_add (struct timespec, struct timespec)
  _GL_ATTRIBUTE_CONST;
struct timespec timespec_sub (struct timespec, struct timespec)
  _GL_ATTRIBUTE_CONST;
struct timespec dtotimespec (double)
  _GL_ATTRIBUTE_CONST;
118 119

/* Return an approximation to A, of type 'double'.  */
120
_GL_TIMESPEC_INLINE double
121 122 123 124 125
timespectod (struct timespec a)
{
  return a.tv_sec + a.tv_nsec / 1e9;
}

126 127 128
struct timespec current_timespec (void);
void gettime (struct timespec *) _GL_ARG_NONNULL ((1));
int settime (struct timespec const *) _GL_ARG_NONNULL ((1));
129

Paul Eggert's avatar
Paul Eggert committed
130 131 132 133
#ifdef __cplusplus
}
#endif

134 135
_GL_INLINE_HEADER_END

136
#endif