blob: b2d3675441bbdd95add425607eb5a352cfd8a261 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include "aos/common/time.h"
2
Brian Silverman0308f162016-01-02 13:32:49 -08003#include <atomic>
4
Brian Silvermanf665d692013-02-17 22:11:39 -08005#include <string.h>
Brian Silvermand0575692015-02-21 16:24:02 -05006#include <inttypes.h>
7
8// We only use global_core from here, which is weak, so we don't really have a
9// dependency on it.
10#include "aos/linux_code/ipc_lib/shared_mem.h"
brians343bc112013-02-10 01:53:46 +000011
12#include "aos/common/logging/logging.h"
Austin Schuhd78ab542013-03-01 22:22:19 -080013#include "aos/common/mutex.h"
brians343bc112013-02-10 01:53:46 +000014
Austin Schuh793d6b92016-05-01 13:28:14 -070015namespace std {
16namespace this_thread {
17template <>
18void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
19 struct timespec end_time_timespec;
20 ::std::chrono::seconds sec =
21 ::std::chrono::duration_cast<::std::chrono::seconds>(
22 end_time.time_since_epoch());
23 ::std::chrono::nanoseconds nsec =
24 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
25 end_time.time_since_epoch() - sec);
26 end_time_timespec.tv_sec = sec.count();
27 end_time_timespec.tv_nsec = nsec.count();
28 int returnval;
29 do {
30 returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
31 &end_time_timespec, nullptr);
32 if (returnval != EINTR && returnval != 0) {
33 PLOG(FATAL, "clock_nanosleep(%jd, TIMER_ABSTIME, %p, nullptr) failed",
34 static_cast<uintmax_t>(CLOCK_MONOTONIC), &end_time_timespec);
35 }
36 } while (returnval != 0);
37}
38
39} // namespace this_thread
40} // namespace std
41
42
brians343bc112013-02-10 01:53:46 +000043namespace aos {
44namespace time {
45
Austin Schuhd78ab542013-03-01 22:22:19 -080046// State required to enable and use mock time.
47namespace {
48// True if mock time is enabled.
49// This does not need to be checked with the mutex held because setting time to
50// be enabled or disabled is atomic, and all future operations are atomic
51// anyways. If there is a race condition setting or clearing whether time is
52// enabled or not, it will still be a race condition if current_mock_time is
53// also set atomically with enabled.
Brian Silverman0308f162016-01-02 13:32:49 -080054::std::atomic<bool> mock_time_enabled{false};
Austin Schuhd78ab542013-03-01 22:22:19 -080055// Mutex to make time reads and writes thread safe.
56Mutex time_mutex;
57// Current time when time is mocked.
58Time current_mock_time(0, 0);
59
60// TODO(aschuh): This doesn't include SleepFor and SleepUntil.
61// TODO(aschuh): Create a clock source object and change the default?
62// That would let me create a MockTime clock source.
Brian Silvermanb407c672014-04-09 11:58:37 -070063
64Time NowImpl(clockid_t clock) {
65 timespec temp;
66 if (clock_gettime(clock, &temp) != 0) {
Brian Silverman01be0002014-05-10 15:44:38 -070067 PLOG(FATAL, "clock_gettime(%jd, %p) failed",
68 static_cast<uintmax_t>(clock), &temp);
Brian Silvermanb407c672014-04-09 11:58:37 -070069 }
Brian Silvermand0575692015-02-21 16:24:02 -050070
Brian Silverman0c715e62015-10-24 16:49:46 -040071 const timespec offset = (&global_core == nullptr || global_core == nullptr ||
72 global_core->mem_struct == nullptr)
Brian Silvermand0575692015-02-21 16:24:02 -050073 ? timespec{0, 0}
74 : global_core->mem_struct->time_offset;
75 return Time(temp) + Time(offset);
brians343bc112013-02-10 01:53:46 +000076}
Austin Schuhd78ab542013-03-01 22:22:19 -080077
Brian Silvermanb407c672014-04-09 11:58:37 -070078} // namespace
79
Brian Silvermandcaa3f72015-11-29 05:32:08 +000080const int32_t Time::kNSecInSec;
81const int32_t Time::kNSecInMSec;
82const int32_t Time::kNSecInUSec;
83const int32_t Time::kMSecInSec;
84const int32_t Time::kUSecInSec;
85
86const Time Time::kZero{0, 0};
87
Brian Silverman6659bc32013-10-16 10:31:32 -070088void Time::EnableMockTime(const Time &now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080089 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -070090 mock_time_enabled = true;
Austin Schuhd78ab542013-03-01 22:22:19 -080091 current_mock_time = now;
92}
93
Brian Silvermanb407c672014-04-09 11:58:37 -070094void Time::UpdateMockTime() {
95 SetMockTime(NowImpl(kDefaultClock));
96}
97
Austin Schuhd78ab542013-03-01 22:22:19 -080098void Time::DisableMockTime() {
99 MutexLocker time_mutex_locker(&time_mutex);
100 mock_time_enabled = false;
101}
102
Brian Silverman6659bc32013-10-16 10:31:32 -0700103void Time::SetMockTime(const Time &now) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800104 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -0700105 if (__builtin_expect(!mock_time_enabled, 0)) {
Austin Schuhd78ab542013-03-01 22:22:19 -0800106 LOG(FATAL, "Tried to set mock time and mock time is not enabled\n");
107 }
108 current_mock_time = now;
109}
110
Brian Silverman6659bc32013-10-16 10:31:32 -0700111void Time::IncrementMockTime(const Time &amount) {
112 static ::aos::Mutex mutex;
113 ::aos::MutexLocker sync(&mutex);
114 SetMockTime(Now() + amount);
115}
116
Austin Schuhd78ab542013-03-01 22:22:19 -0800117Time Time::Now(clockid_t clock) {
Brian Silvermanb407c672014-04-09 11:58:37 -0700118 {
Brian Silverman0308f162016-01-02 13:32:49 -0800119 if (mock_time_enabled.load(::std::memory_order_relaxed)) {
120 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -0700121 return current_mock_time;
Austin Schuhd78ab542013-03-01 22:22:19 -0800122 }
Austin Schuhd78ab542013-03-01 22:22:19 -0800123 }
Brian Silvermanb407c672014-04-09 11:58:37 -0700124 return NowImpl(clock);
Austin Schuhd78ab542013-03-01 22:22:19 -0800125}
126
Brian Silverman52aeeac2013-08-28 16:20:53 -0700127void Time::CheckImpl(int32_t nsec) {
brians343bc112013-02-10 01:53:46 +0000128 static_assert(aos::shm_ok<Time>::value,
129 "it should be able to go through shared memory");
Brian Silverman52aeeac2013-08-28 16:20:53 -0700130 if (nsec >= kNSecInSec || nsec < 0) {
131 LOG(FATAL, "0 <= nsec(%" PRId32 ") < %" PRId32 " isn't true.\n",
132 nsec, kNSecInSec);
133 }
brians343bc112013-02-10 01:53:46 +0000134}
135
136Time &Time::operator+=(const Time &rhs) {
137 sec_ += rhs.sec_;
138 nsec_ += rhs.nsec_;
139 if (nsec_ >= kNSecInSec) {
140 nsec_ -= kNSecInSec;
141 sec_ += 1;
142 }
143 return *this;
144}
145const Time Time::operator+(const Time &rhs) const {
146 return Time(*this) += rhs;
147}
148Time &Time::operator-=(const Time &rhs) {
149 sec_ -= rhs.sec_;
150 nsec_ -= rhs.nsec_;
151 if (nsec_ < 0) {
152 nsec_ += kNSecInSec;
153 sec_ -= 1;
154 }
155 return *this;
156}
157const Time Time::operator-(const Time &rhs) const {
158 return Time(*this) -= rhs;
159}
160Time &Time::operator*=(int32_t rhs) {
161 const int64_t temp = static_cast<int64_t>(nsec_) *
162 static_cast<int64_t>(rhs);
163 sec_ *= rhs; // better not overflow, or the result is just too big
164 nsec_ = temp % kNSecInSec;
165 sec_ += (temp - nsec_) / kNSecInSec;
Brian Silverman6659bc32013-10-16 10:31:32 -0700166 if (nsec_ < 0) {
167 nsec_ += kNSecInSec;
168 sec_ -= 1;
169 }
brians343bc112013-02-10 01:53:46 +0000170 return *this;
171}
172const Time Time::operator*(int32_t rhs) const {
173 return Time(*this) *= rhs;
174}
175Time &Time::operator/=(int32_t rhs) {
176 nsec_ = (sec_ % rhs) * (kNSecInSec / rhs) + nsec_ / rhs;
177 sec_ /= rhs;
Brian Silverman6659bc32013-10-16 10:31:32 -0700178 if (nsec_ < 0) {
179 nsec_ += kNSecInSec;
180 sec_ -= 1;
181 }
brians343bc112013-02-10 01:53:46 +0000182 return *this;
183}
184const Time Time::operator/(int32_t rhs) const {
185 return Time(*this) /= rhs;
186}
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700187double Time::operator/(const Time &rhs) const {
188 return ToSeconds() / rhs.ToSeconds();
189}
brians343bc112013-02-10 01:53:46 +0000190Time &Time::operator%=(int32_t rhs) {
191 nsec_ = ToNSec() % rhs;
Brian Silverman0534df62014-05-26 21:19:15 -0700192 const int wraps = nsec_ / ((rhs / kNSecInSec + 1) * kNSecInSec);
193 sec_ = wraps + rhs / kNSecInSec;
brians343bc112013-02-10 01:53:46 +0000194 nsec_ -= kNSecInSec * wraps;
Brian Silverman6659bc32013-10-16 10:31:32 -0700195 if (nsec_ < 0) {
196 nsec_ += kNSecInSec;
197 sec_ -= 1;
198 }
brians343bc112013-02-10 01:53:46 +0000199 return *this;
200}
201const Time Time::operator%(int32_t rhs) const {
202 return Time(*this) %= rhs;
203}
204
Brian Silverman0079a9d2013-10-24 15:57:35 -0700205const Time Time::operator-() const {
206 return Time(-sec_ - 1, kNSecInSec - nsec_);
207}
208
brians343bc112013-02-10 01:53:46 +0000209bool Time::operator==(const Time &rhs) const {
210 return sec_ == rhs.sec_ && nsec_ == rhs.nsec_;
211}
212bool Time::operator!=(const Time &rhs) const {
213 return !(*this == rhs);
214}
215bool Time::operator<(const Time &rhs) const {
216 return sec_ < rhs.sec_ || (sec_ == rhs.sec_ && nsec_ < rhs.nsec_);
217}
218bool Time::operator>(const Time &rhs) const {
219 return sec_ > rhs.sec_ || (sec_ == rhs.sec_ && nsec_ > rhs.nsec_);
220}
221bool Time::operator<=(const Time &rhs) const {
222 return sec_ < rhs.sec_ || (sec_ == rhs.sec_ && nsec_ <= rhs.nsec_);
223}
224bool Time::operator>=(const Time &rhs) const {
225 return sec_ > rhs.sec_ || (sec_ == rhs.sec_ && nsec_ >= rhs.nsec_);
226}
227
228bool Time::IsWithin(const Time &other, int64_t amount) const {
229 const int64_t temp = ToNSec() - other.ToNSec();
230 return temp <= amount && temp >= -amount;
231}
232
233std::ostream &operator<<(std::ostream &os, const Time& time) {
234 return os << "Time{" << time.sec_ << "s, " << time.nsec_ << "ns}";
235}
236
237void SleepFor(const Time &time, clockid_t clock) {
brians343bc112013-02-10 01:53:46 +0000238 timespec converted(time.ToTimespec()), remaining;
239 int failure = EINTR;
240 do {
241 // This checks whether the last time through the loop actually failed or got
242 // interrupted.
243 if (failure != EINTR) {
Brian Silverman01be0002014-05-10 15:44:38 -0700244 PELOG(FATAL, failure, "clock_nanosleep(%jd, 0, %p, %p) failed",
245 static_cast<intmax_t>(clock), &converted, &remaining);
brians343bc112013-02-10 01:53:46 +0000246 }
247 failure = clock_nanosleep(clock, 0, &converted, &remaining);
248 memcpy(&converted, &remaining, sizeof(converted));
249 } while (failure != 0);
brians343bc112013-02-10 01:53:46 +0000250}
251
252void SleepUntil(const Time &time, clockid_t clock) {
brians343bc112013-02-10 01:53:46 +0000253 timespec converted(time.ToTimespec());
254 int failure;
255 while ((failure = clock_nanosleep(clock, TIMER_ABSTIME,
256 &converted, NULL)) != 0) {
257 if (failure != EINTR) {
Brian Silverman01be0002014-05-10 15:44:38 -0700258 PELOG(FATAL, failure, "clock_nanosleep(%jd, TIMER_ABSTIME, %p, NULL)"
259 " failed", static_cast<intmax_t>(clock), &converted);
brians343bc112013-02-10 01:53:46 +0000260 }
261 }
brians343bc112013-02-10 01:53:46 +0000262}
263
Brian Silvermand0575692015-02-21 16:24:02 -0500264void OffsetToNow(const Time &now) {
Brian Silverman0c715e62015-10-24 16:49:46 -0400265 CHECK_NOTNULL(&global_core);
Brian Silvermand0575692015-02-21 16:24:02 -0500266 CHECK_NOTNULL(global_core);
Brian Silverman0c715e62015-10-24 16:49:46 -0400267 CHECK_NOTNULL(global_core->mem_struct);
Brian Silvermand0575692015-02-21 16:24:02 -0500268 global_core->mem_struct->time_offset.tv_nsec = 0;
269 global_core->mem_struct->time_offset.tv_sec = 0;
270 global_core->mem_struct->time_offset = (now - Time::Now()).ToTimespec();
271}
272
brians343bc112013-02-10 01:53:46 +0000273} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -0800274
275constexpr monotonic_clock::time_point monotonic_clock::min_time;
276
277monotonic_clock::time_point monotonic_clock::now() noexcept {
278 {
279 if (time::mock_time_enabled.load(::std::memory_order_relaxed)) {
280 MutexLocker time_mutex_locker(&time::time_mutex);
281 return monotonic_clock::time_point(
282 ::std::chrono::nanoseconds(time::current_mock_time.ToNSec()));
283 }
284 }
285
286 struct timespec current_time;
287 if (clock_gettime(CLOCK_MONOTONIC, &current_time) != 0) {
288 PLOG(FATAL, "clock_gettime(%jd, %p) failed",
289 static_cast<uintmax_t>(CLOCK_MONOTONIC), &current_time);
290 }
291 return time_point(::std::chrono::seconds(current_time.tv_sec) +
292 ::std::chrono::nanoseconds(current_time.tv_nsec));
293}
294
295
brians343bc112013-02-10 01:53:46 +0000296} // namespace aos