time: add time_check() call and test.
[ccan] / ccan / time / time.c
1 /* Licensed under BSD-MIT - see LICENSE file for details */
2 #include <ccan/time/time.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5
6 #ifdef DEBUG
7 #include <ccan/str/str.h>
8 #define TIME_CHECK(t) time_check((t), __FILE__ ":" stringify(__LINE__))
9 #else
10 #define TIME_CHECK(t) (t)
11 #endif
12
13 #if !HAVE_CLOCK_GETTIME && !HAVE_CLOCK_GETTIME_IN_LIBRT
14 #include <sys/time.h>
15
16 struct timespec time_now(void)
17 {
18         struct timeval now;
19         struct timespec ret;
20         gettimeofday(&now, NULL);
21         ret.tv_sec = now.tv_sec;
22         ret.tv_nsec = now.tv_usec * 1000;
23         return TIME_CHECK(ret);
24 }
25 #else
26 #include <time.h>
27 struct timespec time_now(void)
28 {
29         struct timespec ret;
30         clock_gettime(CLOCK_REALTIME, &ret);
31         return TIME_CHECK(ret);
32 }
33 #endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GETTIME_IN_LIBRT */
34
35 bool time_greater(struct timespec a, struct timespec b)
36 {
37         if (TIME_CHECK(a).tv_sec > TIME_CHECK(b).tv_sec)
38                 return true;
39         else if (a.tv_sec < b.tv_sec)
40                  return false;
41
42         return a.tv_nsec > b.tv_nsec;
43 }
44
45 bool time_less(struct timespec a, struct timespec b)
46 {
47         if (TIME_CHECK(a).tv_sec < TIME_CHECK(b).tv_sec)
48                 return true;
49         else if (a.tv_sec > b.tv_sec)
50                  return false;
51
52         return a.tv_nsec < b.tv_nsec;
53 }
54
55 bool time_eq(struct timespec a, struct timespec b)
56 {
57         return TIME_CHECK(a).tv_sec == TIME_CHECK(b).tv_sec && a.tv_nsec == b.tv_nsec;
58 }
59
60 struct timespec time_sub(struct timespec recent, struct timespec old)
61 {
62         struct timespec diff;
63
64         diff.tv_sec = TIME_CHECK(recent).tv_sec - TIME_CHECK(old).tv_sec;
65         if (old.tv_nsec > recent.tv_nsec) {
66                 diff.tv_sec--;
67                 diff.tv_nsec = 1000000000 + recent.tv_nsec - old.tv_nsec;
68         } else
69                 diff.tv_nsec = recent.tv_nsec - old.tv_nsec;
70
71         return TIME_CHECK(diff);
72 }
73
74 struct timespec time_add(struct timespec a, struct timespec b)
75 {
76         struct timespec sum;
77
78         sum.tv_sec = TIME_CHECK(a).tv_sec + TIME_CHECK(b).tv_sec;
79         sum.tv_nsec = a.tv_nsec + b.tv_nsec;
80         if (sum.tv_nsec >= 1000000000) {
81                 sum.tv_sec++;
82                 sum.tv_nsec -= 1000000000;
83         }
84         return TIME_CHECK(sum);
85 }
86
87 struct timespec time_divide(struct timespec t, unsigned long div)
88 {
89         struct timespec res;
90         uint64_t rem, ns;
91
92         /* Dividing seconds is simple. */
93         res.tv_sec = TIME_CHECK(t).tv_sec / div;
94         rem = t.tv_sec % div;
95
96         /* If we can't fit remainder * 1,000,000,000 in 64 bits? */
97 #if 0 /* ilog is great, but we use fp for multiply anyway. */
98         bits = ilog64(rem);
99         if (bits + 30 >= 64) {
100                 /* Reduce accuracy slightly */
101                 rem >>= (bits - (64 - 30));
102                 div >>= (bits - (64 - 30));
103         }
104 #endif
105         if (rem & ~(((uint64_t)1 << 30) - 1)) {
106                 /* FIXME: fp is cheating! */
107                 double nsec = rem * 1000000000.0 + t.tv_nsec;
108                 res.tv_nsec = nsec / div;
109         } else {
110                 ns = rem * 1000000000 + t.tv_nsec;
111                 res.tv_nsec = ns / div;
112         }
113         return TIME_CHECK(res);
114 }
115
116 struct timespec time_multiply(struct timespec t, unsigned long mult)
117 {
118         struct timespec res;
119
120         /* Are we going to overflow if we multiply nsec? */
121         if (mult & ~((1UL << 30) - 1)) {
122                 /* FIXME: fp is cheating! */
123                 double nsec = (double)t.tv_nsec * mult;
124
125                 res.tv_sec = nsec / 1000000000.0;
126                 res.tv_nsec = nsec - (res.tv_sec * 1000000000.0);
127         } else {
128                 uint64_t nsec = t.tv_nsec * mult;
129
130                 res.tv_nsec = nsec % 1000000000;
131                 res.tv_sec = nsec / 1000000000;
132         }
133         res.tv_sec += TIME_CHECK(t).tv_sec * mult;
134         return TIME_CHECK(res);
135 }
136
137 uint64_t time_to_msec(struct timespec t)
138 {
139         uint64_t msec;
140
141         msec = TIME_CHECK(t).tv_nsec / 1000000 + (uint64_t)t.tv_sec * 1000;
142         return msec;
143 }
144
145 uint64_t time_to_usec(struct timespec t)
146 {
147         uint64_t usec;
148
149         usec = TIME_CHECK(t).tv_nsec / 1000 + (uint64_t)t.tv_sec * 1000000;
150         return usec;
151 }
152
153 uint64_t time_to_nsec(struct timespec t)
154 {
155         uint64_t nsec;
156
157         nsec = TIME_CHECK(t).tv_nsec + (uint64_t)t.tv_sec * 1000000000;
158         return nsec;
159 }
160
161 struct timespec time_from_msec(uint64_t msec)
162 {
163         struct timespec t;
164
165         t.tv_nsec = (msec % 1000) * 1000000;
166         t.tv_sec = msec / 1000;
167         return TIME_CHECK(t);
168 }
169
170 struct timespec time_from_usec(uint64_t usec)
171 {
172         struct timespec t;
173
174         t.tv_nsec = (usec % 1000000) * 1000;
175         t.tv_sec = usec / 1000000;
176         return TIME_CHECK(t);
177 }
178
179 struct timespec time_from_nsec(uint64_t nsec)
180 {
181         struct timespec t;
182
183         t.tv_nsec = nsec % 1000000000;
184         t.tv_sec = nsec / 1000000000;
185         return TIME_CHECK(t);
186 }
187
188 struct timespec time_check(struct timespec t, const char *abortstr)
189 {
190         if (t.tv_sec < 0 || t.tv_nsec >= 1000000000) {
191                 if (abortstr) {
192                         fprintf(stderr, "%s: malformed time %li.%09li\n",
193                                 abortstr,
194                                 (long)t.tv_sec, (long)t.tv_nsec);
195                         abort();
196                 } else {
197                         struct timespec old = t;
198
199                         if (t.tv_nsec >= 1000000000) {
200                                 t.tv_sec += t.tv_nsec / 1000000000;
201                                 t.tv_nsec %= 1000000000;
202                         }
203                         if (t.tv_sec < 0)
204                                 t.tv_sec = 0;
205
206                         fprintf(stderr, "WARNING: malformed time"
207                                 " %li seconds %li ns converted to %li.%09li.\n",
208                                 (long)old.tv_sec, (long)old.tv_nsec,
209                                 (long)t.tv_sec, (long)t.tv_nsec);
210                 }
211         }
212         return t;
213 }