blob: ca1d2076cbbbcee693f9a960d53c64bd0d136b6d [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>
6
7#ifndef __VXWORKS__
8#include <type_traits>
brians57dd5822013-02-27 21:44:15 +00009#include <sys/time.h>
brians343bc112013-02-10 01:53:46 +000010#else
11#include <sysLib.h>
brians57dd5822013-02-27 21:44:15 +000012#include <sys/times.h>
brians343bc112013-02-10 01:53:46 +000013#endif
14#include <ostream>
15
16#include "aos/aos_stdint.h"
17#include "aos/common/type_traits.h"
18
19namespace aos {
20namespace time {
21
22// A nice structure for representing times.
23// 0 <= nsec_ < kNSecInSec should always be true. All functions here will make
24// sure that that is true if it was on all inputs (including *this).
25//
Brian Silverman6659bc32013-10-16 10:31:32 -070026// Negative times are supported so that all of the normal arithmetic identities
27// work. nsec_ is still always positive.
28//
brians343bc112013-02-10 01:53:46 +000029// The arithmetic and comparison operators are overloaded because they make
30// complete sense and are very useful. The default copy and assignment stuff is
Brian Silverman6659bc32013-10-16 10:31:32 -070031// left because it works fine. Multiplication of Times by Times is
brians343bc112013-02-10 01:53:46 +000032// not implemented because I can't think of any uses for them and there are
Brian Silverman6659bc32013-10-16 10:31:32 -070033// multiple ways to do it. Division of Times by Times is implemented as the
34// ratio of them. Multiplication, division, and modulus of Times by integers are
35// implemented as interpreting the argument as nanoseconds.
brians343bc112013-02-10 01:53:46 +000036struct Time {
Brian Silverman52aeeac2013-08-28 16:20:53 -070037#ifdef SWIG
38// All of the uses of constexpr here can safely be simply removed.
39// NOTE: This means that relying on the fact that constexpr implicitly makes
Brian Silverman6659bc32013-10-16 10:31:32 -070040// member functions const is not valid, so they all have to be explicitly marked
41// const.
Brian Silverman52aeeac2013-08-28 16:20:53 -070042#define constexpr
43#endif // SWIG
brians343bc112013-02-10 01:53:46 +000044 public:
45 static const int32_t kNSecInSec = 1000000000;
46 static const int32_t kNSecInMSec = 1000000;
47 static const int32_t kNSecInUSec = 1000;
48 static const int32_t kMSecInSec = 1000;
49 static const int32_t kUSecInSec = 1000000;
Brian Silverman96e6d5a2014-03-24 15:55:40 -070050 constexpr Time(int32_t sec = 0, int32_t nsec = 0)
Brian Silverman52aeeac2013-08-28 16:20:53 -070051 : sec_(sec), nsec_(CheckConstexpr(nsec)) {
brians343bc112013-02-10 01:53:46 +000052 }
53 #ifndef SWIG
Brian Silverman52aeeac2013-08-28 16:20:53 -070054 explicit constexpr Time(const struct timespec &value)
55 : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_nsec)) {
brians343bc112013-02-10 01:53:46 +000056 }
57 struct timespec ToTimespec() const {
58 struct timespec ans;
59 ans.tv_sec = sec_;
60 ans.tv_nsec = nsec_;
61 return ans;
62 }
Brian Silverman52aeeac2013-08-28 16:20:53 -070063 explicit constexpr Time(const struct timeval &value)
64 : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_usec * kNSecInUSec)) {
brians57dd5822013-02-27 21:44:15 +000065 }
66 struct timeval ToTimeval() const {
67 struct timeval ans;
68 ans.tv_sec = sec_;
69 ans.tv_usec = nsec_ / kNSecInUSec;
70 return ans;
71 }
brians343bc112013-02-10 01:53:46 +000072 #endif // SWIG
Brian Silverman3204dd82013-03-12 18:42:01 -070073
Brian Silverman14fd0fb2014-01-14 21:42:01 -080074 // CLOCK_MONOTONIC on linux and CLOCK_REALTIME on the cRIO because the
brians343bc112013-02-10 01:53:46 +000075 // cRIO doesn't have any others.
76 // CLOCK_REALTIME is the default realtime clock and CLOCK_MONOTONIC doesn't
77 // change when somebody changes the wall clock (like the ntp deamon or
78 // whatever). See clock_gettime(2) for details.
79 //
80 // This is the clock that code that just wants to sleep for a certain amount
81 // of time or measure how long something takes should use.
82 #ifndef __VXWORKS__
83 static const clockid_t kDefaultClock = CLOCK_MONOTONIC;
84 #else
85 static const clockid_t kDefaultClock = CLOCK_REALTIME;
86 #endif
87 // Creates a Time representing the current value of the specified clock or
88 // dies.
89 static Time Now(clockid_t clock = kDefaultClock);
90
91 // Constructs a Time representing seconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -070092 static constexpr Time InSeconds(double seconds) {
93 return (seconds < 0.0) ?
94 Time(static_cast<int32_t>(seconds) - 1,
95 (seconds - static_cast<int32_t>(seconds) + 1.0) * kNSecInSec) :
96 Time(static_cast<int32_t>(seconds),
97 (seconds - static_cast<int32_t>(seconds)) * kNSecInSec);
brians343bc112013-02-10 01:53:46 +000098 }
99
100 // Constructs a time representing microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700101 static constexpr Time InNS(int64_t nseconds) {
Brian Silverman6659bc32013-10-16 10:31:32 -0700102 return (nseconds < 0) ?
103 Time(nseconds / static_cast<int64_t>(kNSecInSec) - 1,
104 (nseconds % kNSecInSec) + kNSecInSec) :
105 Time(nseconds / static_cast<int64_t>(kNSecInSec),
106 nseconds % kNSecInSec);
brians343bc112013-02-10 01:53:46 +0000107 }
108
109 // Constructs a time representing microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700110 static constexpr Time InUS(int useconds) {
111 return (useconds < 0) ?
112 Time(useconds / kUSecInSec - 1,
113 (useconds % kUSecInSec) * kNSecInUSec + kNSecInSec) :
114 Time(useconds / kUSecInSec, (useconds % kUSecInSec) * kNSecInUSec);
brians343bc112013-02-10 01:53:46 +0000115 }
116
117 // Constructs a time representing mseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700118 static constexpr Time InMS(int mseconds) {
Brian Silverman6659bc32013-10-16 10:31:32 -0700119 return (mseconds < 0) ?
120 Time(mseconds / kMSecInSec - 1,
121 (mseconds % kMSecInSec) * kNSecInMSec + kNSecInSec) :
122 Time(mseconds / kMSecInSec, (mseconds % kMSecInSec) * kNSecInMSec);
brians343bc112013-02-10 01:53:46 +0000123 }
124
125 // Checks whether or not this time is within amount nanoseconds of other.
126 bool IsWithin(const Time &other, int64_t amount) const;
127
128 // Returns the time represented all in nanoseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700129 int64_t constexpr ToNSec() const {
brians343bc112013-02-10 01:53:46 +0000130 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kNSecInSec) +
131 static_cast<int64_t>(nsec_);
132 }
133#ifdef __VXWORKS__
134 // Returns the time represented all in system clock ticks. The system clock
135 // rate is retrieved using sysClkRateGet().
136 int ToTicks() const {
137 return ToNSec() / static_cast<int64_t>(kNSecInSec / sysClkRateGet());
138 }
Brian Silverman3204dd82013-03-12 18:42:01 -0700139 // Constructs a Time representing ticks.
140 static Time InTicks(int ticks) {
Brian Silvermanffe3d712013-03-15 21:35:59 -0700141 return Time::InSeconds(static_cast<double>(ticks) / sysClkRateGet());
Brian Silverman3204dd82013-03-12 18:42:01 -0700142 }
brians343bc112013-02-10 01:53:46 +0000143#endif
144
145 // Returns the time represented in milliseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700146 int64_t constexpr ToMSec() const {
brians343bc112013-02-10 01:53:46 +0000147 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kMSecInSec) +
148 (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInMSec));
149 }
150
Brian Silverman7645d2f2013-03-30 18:53:56 -0700151 // Returns the time represent in microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700152 int64_t constexpr ToUSec() const {
Brian Silverman7645d2f2013-03-30 18:53:56 -0700153 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kUSecInSec) +
154 (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInUSec));
155 }
156
briansf0165ca2013-03-02 06:17:47 +0000157 // Returns the time represented in fractional seconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700158 double constexpr ToSeconds() const {
briansf0165ca2013-03-02 06:17:47 +0000159 return static_cast<double>(sec_) + static_cast<double>(nsec_) / kNSecInSec;
160 }
161
brians343bc112013-02-10 01:53:46 +0000162 #ifndef SWIG
163 Time &operator+=(const Time &rhs);
164 Time &operator-=(const Time &rhs);
165 Time &operator*=(int32_t rhs);
166 Time &operator/=(int32_t rhs);
167 Time &operator%=(int32_t rhs);
Brian Silverman0079a9d2013-10-24 15:57:35 -0700168 Time &operator%=(double rhs) = delete;
169 Time &operator*=(double rhs) = delete;
170 Time &operator/=(double rhs) = delete;
171 const Time operator*(double rhs) const = delete;
172 const Time operator/(double rhs) const = delete;
173 const Time operator%(double rhs) const = delete;
brians343bc112013-02-10 01:53:46 +0000174 #endif
175 const Time operator+(const Time &rhs) const;
176 const Time operator-(const Time &rhs) const;
177 const Time operator*(int32_t rhs) const;
178 const Time operator/(int32_t rhs) const;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700179 double operator/(const Time &rhs) const;
brians343bc112013-02-10 01:53:46 +0000180 const Time operator%(int32_t rhs) const;
181
Brian Silverman0079a9d2013-10-24 15:57:35 -0700182 const Time operator-() const;
183
brians343bc112013-02-10 01:53:46 +0000184 bool operator==(const Time &rhs) const;
185 bool operator!=(const Time &rhs) const;
186 bool operator<(const Time &rhs) const;
187 bool operator>(const Time &rhs) const;
188 bool operator<=(const Time &rhs) const;
189 bool operator>=(const Time &rhs) const;
190
191 #ifndef SWIG
192 // For gtest etc.
193 friend std::ostream &operator<<(std::ostream &os, const Time &time);
194 #endif // SWIG
195
Brian Silverman52aeeac2013-08-28 16:20:53 -0700196 int32_t constexpr sec() const { return sec_; }
brians343bc112013-02-10 01:53:46 +0000197 void set_sec(int32_t sec) { sec_ = sec; }
Brian Silverman52aeeac2013-08-28 16:20:53 -0700198 int32_t constexpr nsec() const { return nsec_; }
brians343bc112013-02-10 01:53:46 +0000199 void set_nsec(int32_t nsec) {
200 nsec_ = nsec;
201 Check();
202 }
203
Brian Silverman3204dd82013-03-12 18:42:01 -0700204 // Absolute value.
205 Time abs() const {
206 if (*this > Time(0, 0)) return *this;
Brian Silvermanf3cbebd2013-03-19 16:53:18 -0700207 if (nsec_ == 0) return Time(-sec_, 0);
Brian Silverman3204dd82013-03-12 18:42:01 -0700208 return Time(-sec_ - 1, kNSecInSec - nsec_);
209 }
210
211 // Enables returning the mock time value for Now instead of checking the
212 // system clock. This should only be used when testing things depending on
213 // time, or many things may/will break.
Brian Silverman6659bc32013-10-16 10:31:32 -0700214 static void EnableMockTime(const Time &now);
Brian Silverman3204dd82013-03-12 18:42:01 -0700215 // Sets now when time is being mocked.
Brian Silverman6659bc32013-10-16 10:31:32 -0700216 static void SetMockTime(const Time &now);
217 // Convenience function to just increment the mock time by a certain amount in
218 // a thread safe way.
219 static void IncrementMockTime(const Time &amount);
Brian Silverman3204dd82013-03-12 18:42:01 -0700220 // Disables mocking time.
221 static void DisableMockTime();
222
brians343bc112013-02-10 01:53:46 +0000223 private:
224 int32_t sec_, nsec_;
Brian Silverman52aeeac2013-08-28 16:20:53 -0700225
226 // LOG(FATAL)s if nsec is >= kNSecInSec or negative.
227 static void CheckImpl(int32_t nsec);
228 void Check() { CheckImpl(nsec_); }
229 // A constexpr version of CheckImpl that returns the given value when it
Brian Silverman6659bc32013-10-16 10:31:32 -0700230 // succeeds or evaluates to non-constexpr and returns 0 when it fails.
231 // This will result in the usual LOG(FATAL) if this is used where it isn't
232 // required to be constexpr or a compile error if it is.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700233 static constexpr int32_t CheckConstexpr(int32_t nsec) {
234 return (nsec >= kNSecInSec || nsec < 0) ? CheckImpl(nsec), 0 : nsec;
235 }
236
237#ifdef SWIG
238#undef constexpr
239#endif // SWIG
brians343bc112013-02-10 01:53:46 +0000240};
241
242// Sleeps for the amount of time represented by time counted by clock.
243void SleepFor(const Time &time, clockid_t clock = Time::kDefaultClock);
244// Sleeps until clock is at the time represented by time.
245void SleepUntil(const Time &time, clockid_t clock = Time::kDefaultClock);
246
247} // namespace time
248} // namespace aos
249
250#endif // AOS_COMMON_TIME_H_