blob: 6c80451c3a9047844eb95ed1d2ad438064b3acbf [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//
26// The arithmetic and comparison operators are overloaded because they make
27// complete sense and are very useful. The default copy and assignment stuff is
28// left because it works fine. Multiplication and division of Times by Times are
29// not implemented because I can't think of any uses for them and there are
30// multiple ways to do it.
31struct Time {
Brian Silverman52aeeac2013-08-28 16:20:53 -070032#ifdef SWIG
33// All of the uses of constexpr here can safely be simply removed.
34// NOTE: This means that relying on the fact that constexpr implicitly makes
35// member functions const is not safe.
36#define constexpr
37#endif // SWIG
brians343bc112013-02-10 01:53:46 +000038 public:
39 static const int32_t kNSecInSec = 1000000000;
40 static const int32_t kNSecInMSec = 1000000;
41 static const int32_t kNSecInUSec = 1000;
42 static const int32_t kMSecInSec = 1000;
43 static const int32_t kUSecInSec = 1000000;
Brian Silverman52aeeac2013-08-28 16:20:53 -070044 constexpr Time(int32_t sec, int32_t nsec)
45 : sec_(sec), nsec_(CheckConstexpr(nsec)) {
brians343bc112013-02-10 01:53:46 +000046 }
47 #ifndef SWIG
Brian Silverman52aeeac2013-08-28 16:20:53 -070048 explicit constexpr Time(const struct timespec &value)
49 : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_nsec)) {
brians343bc112013-02-10 01:53:46 +000050 }
51 struct timespec ToTimespec() const {
52 struct timespec ans;
53 ans.tv_sec = sec_;
54 ans.tv_nsec = nsec_;
55 return ans;
56 }
Brian Silverman52aeeac2013-08-28 16:20:53 -070057 explicit constexpr Time(const struct timeval &value)
58 : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_usec * kNSecInUSec)) {
brians57dd5822013-02-27 21:44:15 +000059 }
60 struct timeval ToTimeval() const {
61 struct timeval ans;
62 ans.tv_sec = sec_;
63 ans.tv_usec = nsec_ / kNSecInUSec;
64 return ans;
65 }
brians343bc112013-02-10 01:53:46 +000066 #endif // SWIG
Brian Silverman3204dd82013-03-12 18:42:01 -070067
brians343bc112013-02-10 01:53:46 +000068 // CLOCK_MONOTONIC on the fitpc and CLOCK_REALTIME on the cRIO because the
69 // cRIO doesn't have any others.
70 // CLOCK_REALTIME is the default realtime clock and CLOCK_MONOTONIC doesn't
71 // change when somebody changes the wall clock (like the ntp deamon or
72 // whatever). See clock_gettime(2) for details.
73 //
74 // This is the clock that code that just wants to sleep for a certain amount
75 // of time or measure how long something takes should use.
76 #ifndef __VXWORKS__
77 static const clockid_t kDefaultClock = CLOCK_MONOTONIC;
78 #else
79 static const clockid_t kDefaultClock = CLOCK_REALTIME;
80 #endif
81 // Creates a Time representing the current value of the specified clock or
82 // dies.
83 static Time Now(clockid_t clock = kDefaultClock);
84
85 // Constructs a Time representing seconds.
Brian Silverman7645d2f2013-03-30 18:53:56 -070086 // TODO(brians): fix and test the negative cases for all of these
Brian Silverman52aeeac2013-08-28 16:20:53 -070087 static constexpr Time InSeconds(double seconds) {
88 return (seconds < 0.0) ?
89 Time(static_cast<int32_t>(seconds) - 1,
90 (seconds - static_cast<int32_t>(seconds) + 1.0) * kNSecInSec) :
91 Time(static_cast<int32_t>(seconds),
92 (seconds - static_cast<int32_t>(seconds)) * kNSecInSec);
brians343bc112013-02-10 01:53:46 +000093 }
94
95 // Constructs a time representing microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -070096 static constexpr Time InNS(int64_t nseconds) {
brians343bc112013-02-10 01:53:46 +000097 return Time(nseconds / static_cast<int64_t>(kNSecInSec),
98 nseconds % kNSecInSec);
99 }
100
101 // Constructs a time representing microseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700102 static constexpr Time InUS(int useconds) {
103 return (useconds < 0) ?
104 Time(useconds / kUSecInSec - 1,
105 (useconds % kUSecInSec) * kNSecInUSec + kNSecInSec) :
106 Time(useconds / kUSecInSec, (useconds % kUSecInSec) * kNSecInUSec);
brians343bc112013-02-10 01:53:46 +0000107 }
108
109 // Constructs a time representing mseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700110 static constexpr Time InMS(int mseconds) {
brians343bc112013-02-10 01:53:46 +0000111 return Time(mseconds / kMSecInSec, (mseconds % kMSecInSec) * kNSecInMSec);
112 }
113
114 // Checks whether or not this time is within amount nanoseconds of other.
115 bool IsWithin(const Time &other, int64_t amount) const;
116
117 // Returns the time represented all in nanoseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700118 int64_t constexpr ToNSec() const {
brians343bc112013-02-10 01:53:46 +0000119 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kNSecInSec) +
120 static_cast<int64_t>(nsec_);
121 }
122#ifdef __VXWORKS__
123 // Returns the time represented all in system clock ticks. The system clock
124 // rate is retrieved using sysClkRateGet().
125 int ToTicks() const {
126 return ToNSec() / static_cast<int64_t>(kNSecInSec / sysClkRateGet());
127 }
Brian Silverman3204dd82013-03-12 18:42:01 -0700128 // Constructs a Time representing ticks.
129 static Time InTicks(int ticks) {
Brian Silvermanffe3d712013-03-15 21:35:59 -0700130 return Time::InSeconds(static_cast<double>(ticks) / sysClkRateGet());
Brian Silverman3204dd82013-03-12 18:42:01 -0700131 }
brians343bc112013-02-10 01:53:46 +0000132#endif
133
134 // Returns the time represented in milliseconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700135 int64_t constexpr ToMSec() const {
brians343bc112013-02-10 01:53:46 +0000136 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kMSecInSec) +
137 (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInMSec));
138 }
139
Brian Silverman7645d2f2013-03-30 18:53:56 -0700140 // Returns the time represent in microseconds.
141 // TODO(brians): test this
Brian Silverman52aeeac2013-08-28 16:20:53 -0700142 int64_t constexpr ToUSec() const {
Brian Silverman7645d2f2013-03-30 18:53:56 -0700143 return static_cast<int64_t>(sec_) * static_cast<int64_t>(kUSecInSec) +
144 (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInUSec));
145 }
146
briansf0165ca2013-03-02 06:17:47 +0000147 // Returns the time represented in fractional seconds.
Brian Silverman52aeeac2013-08-28 16:20:53 -0700148 double constexpr ToSeconds() const {
briansf0165ca2013-03-02 06:17:47 +0000149 return static_cast<double>(sec_) + static_cast<double>(nsec_) / kNSecInSec;
150 }
151
brians343bc112013-02-10 01:53:46 +0000152 #ifndef SWIG
153 Time &operator+=(const Time &rhs);
154 Time &operator-=(const Time &rhs);
155 Time &operator*=(int32_t rhs);
156 Time &operator/=(int32_t rhs);
157 Time &operator%=(int32_t rhs);
158 #endif
159 const Time operator+(const Time &rhs) const;
160 const Time operator-(const Time &rhs) const;
161 const Time operator*(int32_t rhs) const;
162 const Time operator/(int32_t rhs) const;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700163 // TODO(brians) test this
164 double operator/(const Time &rhs) const;
brians343bc112013-02-10 01:53:46 +0000165 const Time operator%(int32_t rhs) const;
166
167 bool operator==(const Time &rhs) const;
168 bool operator!=(const Time &rhs) const;
169 bool operator<(const Time &rhs) const;
170 bool operator>(const Time &rhs) const;
171 bool operator<=(const Time &rhs) const;
172 bool operator>=(const Time &rhs) const;
173
174 #ifndef SWIG
175 // For gtest etc.
176 friend std::ostream &operator<<(std::ostream &os, const Time &time);
177 #endif // SWIG
178
Brian Silverman52aeeac2013-08-28 16:20:53 -0700179 int32_t constexpr sec() const { return sec_; }
brians343bc112013-02-10 01:53:46 +0000180 void set_sec(int32_t sec) { sec_ = sec; }
Brian Silverman52aeeac2013-08-28 16:20:53 -0700181 int32_t constexpr nsec() const { return nsec_; }
brians343bc112013-02-10 01:53:46 +0000182 void set_nsec(int32_t nsec) {
183 nsec_ = nsec;
184 Check();
185 }
186
Brian Silverman3204dd82013-03-12 18:42:01 -0700187 // Absolute value.
188 Time abs() const {
189 if (*this > Time(0, 0)) return *this;
Brian Silvermanf3cbebd2013-03-19 16:53:18 -0700190 if (nsec_ == 0) return Time(-sec_, 0);
Brian Silverman3204dd82013-03-12 18:42:01 -0700191 return Time(-sec_ - 1, kNSecInSec - nsec_);
192 }
193
194 // Enables returning the mock time value for Now instead of checking the
195 // system clock. This should only be used when testing things depending on
196 // time, or many things may/will break.
197 static void EnableMockTime(const Time now);
198 // Sets now when time is being mocked.
199 static void SetMockTime(const Time now);
200 // Convenience function to just increment the mock time by a certain amount.
201 static void IncrementMockTime(const Time amount) {
Brian Silvermanf3cbebd2013-03-19 16:53:18 -0700202 // TODO(brians) make this thread safe so it's more useful?
Brian Silverman3204dd82013-03-12 18:42:01 -0700203 SetMockTime(Now() + amount);
204 }
205 // Disables mocking time.
206 static void DisableMockTime();
207
brians343bc112013-02-10 01:53:46 +0000208 private:
209 int32_t sec_, nsec_;
Brian Silverman52aeeac2013-08-28 16:20:53 -0700210
211 // LOG(FATAL)s if nsec is >= kNSecInSec or negative.
212 static void CheckImpl(int32_t nsec);
213 void Check() { CheckImpl(nsec_); }
214 // A constexpr version of CheckImpl that returns the given value when it
215 // succeeds.
216 static constexpr int32_t CheckConstexpr(int32_t nsec) {
217 return (nsec >= kNSecInSec || nsec < 0) ? CheckImpl(nsec), 0 : nsec;
218 }
219
220#ifdef SWIG
221#undef constexpr
222#endif // SWIG
brians343bc112013-02-10 01:53:46 +0000223};
224
225// Sleeps for the amount of time represented by time counted by clock.
226void SleepFor(const Time &time, clockid_t clock = Time::kDefaultClock);
227// Sleeps until clock is at the time represented by time.
228void SleepUntil(const Time &time, clockid_t clock = Time::kDefaultClock);
229
230} // namespace time
231} // namespace aos
232
233#endif // AOS_COMMON_TIME_H_