blob: 9afe9a05607d6c0df4aaea9480092eed907be592 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#ifndef AOS_COMMON_TIME_H_
2#define AOS_COMMON_TIME_H_
3
4#include <stdint.h>
5#include <time.h>
brians57dd5822013-02-27 21:44:15 +00006#include <sys/time.h>
Brian4a424a22014-04-02 11:52:45 -07007#include <stdint.h>
8
9#include <type_traits>
brians343bc112013-02-10 01:53:46 +000010#include <ostream>
11
brians343bc112013-02-10 01:53:46 +000012#include "aos/common/type_traits.h"
Brian Silvermanb407c672014-04-09 11:58:37 -070013#include "aos/common/macros.h"
brians343bc112013-02-10 01:53:46 +000014
15namespace aos {
16namespace time {
17
18// A nice structure for representing times.
19// 0 <= nsec_ < kNSecInSec should always be true. All functions here will make
20// sure that that is true if it was on all inputs (including *this).
21//
Brian Silverman6659bc32013-10-16 10:31:32 -070022// Negative times are supported so that all of the normal arithmetic identities
23// work. nsec_ is still always positive.
24//
brians343bc112013-02-10 01:53:46 +000025// The arithmetic and comparison operators are overloaded because they make
26// complete sense and are very useful. The default copy and assignment stuff is
Brian Silverman6659bc32013-10-16 10:31:32 -070027// left because it works fine. Multiplication of Times by Times is
brians343bc112013-02-10 01:53:46 +000028// not implemented because I can't think of any uses for them and there are
Brian Silverman6659bc32013-10-16 10:31:32 -070029// multiple ways to do it. Division of Times by Times is implemented as the
30// ratio of them. Multiplication, division, and modulus of Times by integers are
Brian Silverman0534df62014-05-26 21:19:15 -070031// implemented as interpreting the argument as nanoseconds. Modulus takes the
32// sign from the first operand.
brians343bc112013-02-10 01:53:46 +000033struct Time {
Brian Silverman52aeeac2013-08-28 16:20:53 -070034#ifdef SWIG
35// All of the uses of constexpr here can safely be simply removed.
36// NOTE: This means that relying on the fact that constexpr implicitly makes
Brian Silverman6659bc32013-10-16 10:31:32 -070037// member functions const is not valid, so they all have to be explicitly marked
38// const.
Brian Silverman52aeeac2013-08-28 16:20:53 -070039#define constexpr
40#endif // SWIG
brians343bc112013-02-10 01:53:46 +000041 public:
42 static const int32_t kNSecInSec = 1000000000;
43 static const int32_t kNSecInMSec = 1000000;
44 static const int32_t kNSecInUSec = 1000;
45 static const int32_t kMSecInSec = 1000;
46 static const int32_t kUSecInSec = 1000000;
Brian Silverman96e6d5a2014-03-24 15:55:40 -070047 constexpr Time(int32_t sec = 0, int32_t nsec = 0)
Brian Silverman52aeeac2013-08-28 16:20:53 -070048 : sec_(sec), nsec_(CheckConstexpr(nsec)) {
brians343bc112013-02-10 01:53:46 +000049 }
50 #ifndef SWIG
Brian Silverman52aeeac2013-08-28 16:20:53 -070051 explicit constexpr Time(const struct timespec &value)
52 : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_nsec)) {
brians343bc112013-02-10 01:53:46 +000053 }
54 struct timespec ToTimespec() const {
55 struct timespec ans;
56 ans.tv_sec = sec_;
57 ans.tv_nsec = nsec_;
58 return ans;
59 }
Brian Silverman52aeeac2013-08-28 16:20:53 -070060 explicit constexpr Time(const struct timeval &value)
61 : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_usec * kNSecInUSec)) {
brians57dd5822013-02-27 21:44:15 +000062 }
63 struct timeval ToTimeval() const {
64 struct timeval ans;
65 ans.tv_sec = sec_;
66 ans.tv_usec = nsec_ / kNSecInUSec;
67 return ans;
68 }
brians343bc112013-02-10 01:53:46 +000069 #endif // SWIG
Brian Silverman3204dd82013-03-12 18:42:01 -070070
Brian Silverman14fd0fb2014-01-14 21:42:01 -080071 // CLOCK_MONOTONIC on linux and CLOCK_REALTIME on the cRIO because the
brians343bc112013-02-10 01:53:46 +000072 // cRIO doesn't have any others.
73 // CLOCK_REALTIME is the default realtime clock and CLOCK_MONOTONIC doesn't
74 // change when somebody changes the wall clock (like the ntp deamon or
75 // whatever). See clock_gettime(2) for details.
76 //
77 // This is the clock that code that just wants to sleep for a certain amount
78 // of time or measure how long something takes should use.
79 #ifndef __VXWORKS__
80 static const clockid_t kDefaultClock = CLOCK_MONOTONIC;
81 #else
82 static const clockid_t kDefaultClock = CLOCK_REALTIME;
83 #endif
84 // Creates a Time representing the current value of the specified clock or
85 // dies.
86 static Time Now(clockid_t clock = kDefaultClock);
87
88 // Constructs a Time representing seconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -070089 static constexpr Time InSeconds(double seconds) {
90 return (seconds < 0.0) ?
91 Time(static_cast<int32_t>(seconds) - 1,
92 (seconds - static_cast<int32_t>(seconds) + 1.0) * kNSecInSec) :
93 Time(static_cast<int32_t>(seconds),
94 (seconds - static_cast<int32_t>(seconds)) * kNSecInSec);
brians343bc112013-02-10 01:53:46 +000095 }
96
97 // Constructs a time representing microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -070098 static constexpr Time InNS(int64_t nseconds) {
Brian Silverman6659bc32013-10-16 10:31:32 -070099 return (nseconds < 0) ?
100 Time(nseconds / static_cast<int64_t>(kNSecInSec) - 1,
101 (nseconds % kNSecInSec) + kNSecInSec) :
102 Time(nseconds / static_cast<int64_t>(kNSecInSec),
103 nseconds % kNSecInSec);
brians343bc112013-02-10 01:53:46 +0000104 }
105
106 // Constructs a time representing microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700107 static constexpr Time InUS(int useconds) {
108 return (useconds < 0) ?
109 Time(useconds / kUSecInSec - 1,
110 (useconds % kUSecInSec) * kNSecInUSec + kNSecInSec) :
111 Time(useconds / kUSecInSec, (useconds % kUSecInSec) * kNSecInUSec);
brians343bc112013-02-10 01:53:46 +0000112 }
113
114 // Constructs a time representing mseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700115 static constexpr Time InMS(int mseconds) {
Brian Silverman6659bc32013-10-16 10:31:32 -0700116 return (mseconds < 0) ?
117 Time(mseconds / kMSecInSec - 1,
118 (mseconds % kMSecInSec) * kNSecInMSec + kNSecInSec) :
119 Time(mseconds / kMSecInSec, (mseconds % kMSecInSec) * kNSecInMSec);
brians343bc112013-02-10 01:53:46 +0000120 }
121
122 // Checks whether or not this time is within amount nanoseconds of other.
123 bool IsWithin(const Time &other, int64_t amount) const;
124
125 // Returns the time represented all in nanoseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700126 int64_t constexpr ToNSec() const {
brians343bc112013-02-10 01:53:46 +0000127 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kNSecInSec) +
128 static_cast<int64_t>(nsec_);
129 }
130#ifdef __VXWORKS__
131 // Returns the time represented all in system clock ticks. The system clock
132 // rate is retrieved using sysClkRateGet().
133 int ToTicks() const {
134 return ToNSec() / static_cast<int64_t>(kNSecInSec / sysClkRateGet());
135 }
Brian Silverman3204dd82013-03-12 18:42:01 -0700136 // Constructs a Time representing ticks.
137 static Time InTicks(int ticks) {
Brian Silvermanffe3d712013-03-15 21:35:59 -0700138 return Time::InSeconds(static_cast<double>(ticks) / sysClkRateGet());
Brian Silverman3204dd82013-03-12 18:42:01 -0700139 }
brians343bc112013-02-10 01:53:46 +0000140#endif
141
142 // Returns the time represented in milliseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700143 int64_t constexpr ToMSec() const {
brians343bc112013-02-10 01:53:46 +0000144 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kMSecInSec) +
145 (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInMSec));
146 }
147
Brian Silverman7645d2f2013-03-30 18:53:56 -0700148 // Returns the time represent in microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700149 int64_t constexpr ToUSec() const {
Brian Silverman7645d2f2013-03-30 18:53:56 -0700150 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kUSecInSec) +
151 (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInUSec));
152 }
153
briansf0165ca2013-03-02 06:17:47 +0000154 // Returns the time represented in fractional seconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700155 double constexpr ToSeconds() const {
briansf0165ca2013-03-02 06:17:47 +0000156 return static_cast<double>(sec_) + static_cast<double>(nsec_) / kNSecInSec;
157 }
158
brians343bc112013-02-10 01:53:46 +0000159 #ifndef SWIG
160 Time &operator+=(const Time &rhs);
161 Time &operator-=(const Time &rhs);
162 Time &operator*=(int32_t rhs);
163 Time &operator/=(int32_t rhs);
164 Time &operator%=(int32_t rhs);
Brian Silverman0079a9d2013-10-24 15:57:35 -0700165 Time &operator%=(double rhs) = delete;
166 Time &operator*=(double rhs) = delete;
167 Time &operator/=(double rhs) = delete;
168 const Time operator*(double rhs) const = delete;
169 const Time operator/(double rhs) const = delete;
170 const Time operator%(double rhs) const = delete;
brians343bc112013-02-10 01:53:46 +0000171 #endif
172 const Time operator+(const Time &rhs) const;
173 const Time operator-(const Time &rhs) const;
174 const Time operator*(int32_t rhs) const;
175 const Time operator/(int32_t rhs) const;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700176 double operator/(const Time &rhs) const;
brians343bc112013-02-10 01:53:46 +0000177 const Time operator%(int32_t rhs) const;
178
Brian Silverman0079a9d2013-10-24 15:57:35 -0700179 const Time operator-() const;
180
brians343bc112013-02-10 01:53:46 +0000181 bool operator==(const Time &rhs) const;
182 bool operator!=(const Time &rhs) const;
183 bool operator<(const Time &rhs) const;
184 bool operator>(const Time &rhs) const;
185 bool operator<=(const Time &rhs) const;
186 bool operator>=(const Time &rhs) const;
187
188 #ifndef SWIG
189 // For gtest etc.
190 friend std::ostream &operator<<(std::ostream &os, const Time &time);
191 #endif // SWIG
192
Brian Silverman52aeeac2013-08-28 16:20:53 -0700193 int32_t constexpr sec() const { return sec_; }
brians343bc112013-02-10 01:53:46 +0000194 void set_sec(int32_t sec) { sec_ = sec; }
Brian Silverman52aeeac2013-08-28 16:20:53 -0700195 int32_t constexpr nsec() const { return nsec_; }
brians343bc112013-02-10 01:53:46 +0000196 void set_nsec(int32_t nsec) {
197 nsec_ = nsec;
198 Check();
199 }
200
Brian Silverman3204dd82013-03-12 18:42:01 -0700201 // Absolute value.
202 Time abs() const {
203 if (*this > Time(0, 0)) return *this;
Brian Silvermanf3cbebd2013-03-19 16:53:18 -0700204 if (nsec_ == 0) return Time(-sec_, 0);
Brian Silverman3204dd82013-03-12 18:42:01 -0700205 return Time(-sec_ - 1, kNSecInSec - nsec_);
206 }
207
208 // Enables returning the mock time value for Now instead of checking the
Brian Silverman6da04272014-05-18 18:47:48 -0700209 // system clock.
Brian Silvermanb407c672014-04-09 11:58:37 -0700210 static void EnableMockTime(const Time &now = Now());
211 // Calls SetMockTime with the current actual time.
212 static void UpdateMockTime();
Brian Silverman3204dd82013-03-12 18:42:01 -0700213 // Sets now when time is being mocked.
Brian Silverman6659bc32013-10-16 10:31:32 -0700214 static void SetMockTime(const Time &now);
215 // Convenience function to just increment the mock time by a certain amount in
216 // a thread safe way.
217 static void IncrementMockTime(const Time &amount);
Brian Silverman3204dd82013-03-12 18:42:01 -0700218 // Disables mocking time.
219 static void DisableMockTime();
220
brians343bc112013-02-10 01:53:46 +0000221 private:
222 int32_t sec_, nsec_;
Brian Silverman52aeeac2013-08-28 16:20:53 -0700223
224 // LOG(FATAL)s if nsec is >= kNSecInSec or negative.
225 static void CheckImpl(int32_t nsec);
226 void Check() { CheckImpl(nsec_); }
227 // A constexpr version of CheckImpl that returns the given value when it
Brian Silverman6659bc32013-10-16 10:31:32 -0700228 // succeeds or evaluates to non-constexpr and returns 0 when it fails.
229 // This will result in the usual LOG(FATAL) if this is used where it isn't
230 // required to be constexpr or a compile error if it is.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700231 static constexpr int32_t CheckConstexpr(int32_t nsec) {
232 return (nsec >= kNSecInSec || nsec < 0) ? CheckImpl(nsec), 0 : nsec;
233 }
234
235#ifdef SWIG
236#undef constexpr
237#endif // SWIG
brians343bc112013-02-10 01:53:46 +0000238};
239
240// Sleeps for the amount of time represented by time counted by clock.
241void SleepFor(const Time &time, clockid_t clock = Time::kDefaultClock);
242// Sleeps until clock is at the time represented by time.
243void SleepUntil(const Time &time, clockid_t clock = Time::kDefaultClock);
244
Brian Silvermand0575692015-02-21 16:24:02 -0500245// Sets the global offset for all times so ::aos::time::Time::Now() will return
246// now.
247// There is no synchronization here, so this is only safe when only a single
248// task is running.
249// This is only allowed when the shared memory core infrastructure has been
250// initialized in this process.
251void OffsetToNow(const Time &now);
252
Brian Silvermanb407c672014-04-09 11:58:37 -0700253// RAII class that freezes Time::Now() (to avoid making large numbers of
254// syscalls to find the real time).
255class TimeFreezer {
256 public:
257 TimeFreezer() {
258 Time::EnableMockTime();
259 }
260 ~TimeFreezer() {
261 Time::DisableMockTime();
262 }
263
264 private:
265 DISALLOW_COPY_AND_ASSIGN(TimeFreezer);
266};
267
brians343bc112013-02-10 01:53:46 +0000268} // namespace time
269} // namespace aos
270
271#endif // AOS_COMMON_TIME_H_