]> git.ozlabs.org Git - ccan/blob - ccan/time/time.c
base64: fix for unsigned chars (e.g. ARM).
[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
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 */
27
28 struct timemono time_mono(void)
29 {
30         struct timemono ret;
31 #if TIME_HAVE_MONOTONIC
32         clock_gettime(CLOCK_MONOTONIC, &ret.ts);
33 #else /* Best we can do */
34         ret.ts = time_now().ts;
35 #endif /* !HAVE_TIME_MONOTONIC */
36         return TIMEMONO_CHECK(ret);
37 }
38
39 struct timerel time_divide(struct timerel t, unsigned long div)
40 {
41         struct timerel res;
42         uint64_t rem, ns;
43
44         /* Dividing seconds is simple. */
45         res.ts.tv_sec = TIMEREL_CHECK(t).ts.tv_sec / div;
46         rem = t.ts.tv_sec % div;
47
48         /* If we can't fit remainder * 1,000,000,000 in 64 bits? */
49 #if 0 /* ilog is great, but we use fp for multiply anyway. */
50         bits = ilog64(rem);
51         if (bits + 30 >= 64) {
52                 /* Reduce accuracy slightly */
53                 rem >>= (bits - (64 - 30));
54                 div >>= (bits - (64 - 30));
55         }
56 #endif
57         if (rem & ~(((uint64_t)1 << 30) - 1)) {
58                 /* FIXME: fp is cheating! */
59                 double nsec = rem * 1000000000.0 + t.ts.tv_nsec;
60                 res.ts.tv_nsec = nsec / div;
61         } else {
62                 ns = rem * 1000000000 + t.ts.tv_nsec;
63                 res.ts.tv_nsec = ns / div;
64         }
65         return TIMEREL_CHECK(res);
66 }
67
68 struct timerel time_multiply(struct timerel t, unsigned long mult)
69 {
70         struct timerel res;
71
72         /* Are we going to overflow if we multiply nsec? */
73         if (mult & ~((1UL << 30) - 1)) {
74                 /* FIXME: fp is cheating! */
75                 double nsec = (double)t.ts.tv_nsec * mult;
76
77                 res.ts.tv_sec = nsec / 1000000000.0;
78                 res.ts.tv_nsec = nsec - (res.ts.tv_sec * 1000000000.0);
79         } else {
80                 uint64_t nsec = t.ts.tv_nsec * mult;
81
82                 res.ts.tv_nsec = nsec % 1000000000;
83                 res.ts.tv_sec = nsec / 1000000000;
84         }
85         res.ts.tv_sec += TIMEREL_CHECK(t).ts.tv_sec * mult;
86         return TIMEREL_CHECK(res);
87 }
88
89 struct timespec time_check_(struct timespec t, const char *abortstr)
90 {
91         if (t.tv_sec < 0 || t.tv_nsec >= 1000000000) {
92                 if (abortstr) {
93                         fprintf(stderr, "%s: malformed time %li.%09li\n",
94                                 abortstr,
95                                 (long)t.tv_sec, (long)t.tv_nsec);
96                         abort();
97                 } else {
98                         struct timespec old = t;
99
100                         if (t.tv_nsec >= 1000000000) {
101                                 t.tv_sec += t.tv_nsec / 1000000000;
102                                 t.tv_nsec %= 1000000000;
103                         }
104                         if (t.tv_sec < 0)
105                                 t.tv_sec = 0;
106
107                         fprintf(stderr, "WARNING: malformed time"
108                                 " %li seconds %li ns converted to %li.%09li.\n",
109                                 (long)old.tv_sec, (long)old.tv_nsec,
110                                 (long)t.tv_sec, (long)t.tv_nsec);
111                 }
112         }
113         return t;
114 }
115
116 struct timerel timerel_check(struct timerel t, const char *abortstr)
117 {
118         struct timerel ret;
119
120         ret.ts = time_check_(t.ts, abortstr);
121         return ret;
122 }
123
124 struct timeabs timeabs_check(struct timeabs t, const char *abortstr)
125 {
126         struct timeabs ret;
127
128         ret.ts = time_check_(t.ts, abortstr);
129         return ret;
130 }
131
132 struct timemono timemono_check(struct timemono t, const char *abortstr)
133 {
134         struct timemono ret;
135
136         ret.ts = time_check_(t.ts, abortstr);
137         return ret;
138 }