time: split absolute and relative times.
[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 #if !HAVE_CLOCK_GETTIME && !HAVE_CLOCK_GETTIME_IN_LIBRT
7 #include <sys/time.h>
8
9 struct timeabs time_now(void)
10 {
11         struct timeval now;
12         struct timeabs ret;
13         gettimeofday(&now, NULL);
14         ret.ts.tv_sec = now.tv_sec;
15         ret.ts.tv_nsec = now.tv_usec * 1000;
16         return TIMEABS_CHECK(ret);
17 }
18 #else
19 #include <time.h>
20 struct timeabs time_now(void)
21 {
22         struct timeabs ret;
23         clock_gettime(CLOCK_REALTIME, &ret.ts);
24         return TIMEABS_CHECK(ret);
25 }
26 #endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GETTIME_IN_LIBRT */
27
28 struct timerel time_divide(struct timerel t, unsigned long div)
29 {
30         struct timerel res;
31         uint64_t rem, ns;
32
33         /* Dividing seconds is simple. */
34         res.ts.tv_sec = TIMEREL_CHECK(t).ts.tv_sec / div;
35         rem = t.ts.tv_sec % div;
36
37         /* If we can't fit remainder * 1,000,000,000 in 64 bits? */
38 #if 0 /* ilog is great, but we use fp for multiply anyway. */
39         bits = ilog64(rem);
40         if (bits + 30 >= 64) {
41                 /* Reduce accuracy slightly */
42                 rem >>= (bits - (64 - 30));
43                 div >>= (bits - (64 - 30));
44         }
45 #endif
46         if (rem & ~(((uint64_t)1 << 30) - 1)) {
47                 /* FIXME: fp is cheating! */
48                 double nsec = rem * 1000000000.0 + t.ts.tv_nsec;
49                 res.ts.tv_nsec = nsec / div;
50         } else {
51                 ns = rem * 1000000000 + t.ts.tv_nsec;
52                 res.ts.tv_nsec = ns / div;
53         }
54         return TIMEREL_CHECK(res);
55 }
56
57 struct timerel time_multiply(struct timerel t, unsigned long mult)
58 {
59         struct timerel res;
60
61         /* Are we going to overflow if we multiply nsec? */
62         if (mult & ~((1UL << 30) - 1)) {
63                 /* FIXME: fp is cheating! */
64                 double nsec = (double)t.ts.tv_nsec * mult;
65
66                 res.ts.tv_sec = nsec / 1000000000.0;
67                 res.ts.tv_nsec = nsec - (res.ts.tv_sec * 1000000000.0);
68         } else {
69                 uint64_t nsec = t.ts.tv_nsec * mult;
70
71                 res.ts.tv_nsec = nsec % 1000000000;
72                 res.ts.tv_sec = nsec / 1000000000;
73         }
74         res.ts.tv_sec += TIMEREL_CHECK(t).ts.tv_sec * mult;
75         return TIMEREL_CHECK(res);
76 }
77
78 struct timespec time_check_(struct timespec t, const char *abortstr)
79 {
80         if (t.tv_sec < 0 || t.tv_nsec >= 1000000000) {
81                 if (abortstr) {
82                         fprintf(stderr, "%s: malformed time %li.%09li\n",
83                                 abortstr,
84                                 (long)t.tv_sec, (long)t.tv_nsec);
85                         abort();
86                 } else {
87                         struct timespec old = t;
88
89                         if (t.tv_nsec >= 1000000000) {
90                                 t.tv_sec += t.tv_nsec / 1000000000;
91                                 t.tv_nsec %= 1000000000;
92                         }
93                         if (t.tv_sec < 0)
94                                 t.tv_sec = 0;
95
96                         fprintf(stderr, "WARNING: malformed time"
97                                 " %li seconds %li ns converted to %li.%09li.\n",
98                                 (long)old.tv_sec, (long)old.tv_nsec,
99                                 (long)t.tv_sec, (long)t.tv_nsec);
100                 }
101         }
102         return t;
103 }
104
105 struct timerel timerel_check(struct timerel t, const char *abortstr)
106 {
107         struct timerel ret;
108
109         ret.ts = time_check_(t.ts, abortstr);
110         return ret;
111 }
112
113 struct timeabs timeabs_check(struct timeabs t, const char *abortstr)
114 {
115         struct timeabs ret;
116
117         ret.ts = time_check_(t.ts, abortstr);
118         return ret;
119 }