blob: 0fe3ee369d80dd0e72eeb329f22d2412d8816950 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include "aos/common/time.h"
2
Brian Silvermand0575692015-02-21 16:24:02 -05003#include <inttypes.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08004#include <string.h>
5
6#include <atomic>
7#include <chrono>
Brian Silvermand0575692015-02-21 16:24:02 -05008
9// We only use global_core from here, which is weak, so we don't really have a
10// dependency on it.
11#include "aos/linux_code/ipc_lib/shared_mem.h"
brians343bc112013-02-10 01:53:46 +000012
13#include "aos/common/logging/logging.h"
Austin Schuhd78ab542013-03-01 22:22:19 -080014#include "aos/common/mutex.h"
brians343bc112013-02-10 01:53:46 +000015
Austin Schuhf2a50ba2016-12-24 16:16:26 -080016namespace chrono = ::std::chrono;
17
Austin Schuh793d6b92016-05-01 13:28:14 -070018namespace std {
19namespace this_thread {
20template <>
21void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
22 struct timespec end_time_timespec;
23 ::std::chrono::seconds sec =
24 ::std::chrono::duration_cast<::std::chrono::seconds>(
25 end_time.time_since_epoch());
26 ::std::chrono::nanoseconds nsec =
27 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
28 end_time.time_since_epoch() - sec);
29 end_time_timespec.tv_sec = sec.count();
30 end_time_timespec.tv_nsec = nsec.count();
31 int returnval;
32 do {
33 returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
34 &end_time_timespec, nullptr);
35 if (returnval != EINTR && returnval != 0) {
36 PLOG(FATAL, "clock_nanosleep(%jd, TIMER_ABSTIME, %p, nullptr) failed",
37 static_cast<uintmax_t>(CLOCK_MONOTONIC), &end_time_timespec);
38 }
39 } while (returnval != 0);
40}
41
42} // namespace this_thread
43} // namespace std
44
45
brians343bc112013-02-10 01:53:46 +000046namespace aos {
47namespace time {
48
Austin Schuhd78ab542013-03-01 22:22:19 -080049// State required to enable and use mock time.
50namespace {
51// True if mock time is enabled.
52// This does not need to be checked with the mutex held because setting time to
53// be enabled or disabled is atomic, and all future operations are atomic
54// anyways. If there is a race condition setting or clearing whether time is
55// enabled or not, it will still be a race condition if current_mock_time is
56// also set atomically with enabled.
Brian Silverman0308f162016-01-02 13:32:49 -080057::std::atomic<bool> mock_time_enabled{false};
Austin Schuhd78ab542013-03-01 22:22:19 -080058// Mutex to make time reads and writes thread safe.
59Mutex time_mutex;
60// Current time when time is mocked.
Austin Schuh6a6f90c2016-11-25 21:36:42 -080061monotonic_clock::time_point current_mock_time = monotonic_clock::epoch();
Austin Schuhd78ab542013-03-01 22:22:19 -080062
Brian Silvermanb407c672014-04-09 11:58:37 -070063} // namespace
64
Austin Schuh6a6f90c2016-11-25 21:36:42 -080065void EnableMockTime(monotonic_clock::time_point now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080066 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -070067 mock_time_enabled = true;
Austin Schuhd78ab542013-03-01 22:22:19 -080068 current_mock_time = now;
69}
70
Austin Schuh6a6f90c2016-11-25 21:36:42 -080071void UpdateMockTime() { SetMockTime(monotonic_clock::now()); }
Brian Silvermanb407c672014-04-09 11:58:37 -070072
Austin Schuh6a6f90c2016-11-25 21:36:42 -080073void DisableMockTime() {
Austin Schuhd78ab542013-03-01 22:22:19 -080074 MutexLocker time_mutex_locker(&time_mutex);
75 mock_time_enabled = false;
76}
77
Austin Schuh6a6f90c2016-11-25 21:36:42 -080078void SetMockTime(monotonic_clock::time_point now) {
Austin Schuhd78ab542013-03-01 22:22:19 -080079 MutexLocker time_mutex_locker(&time_mutex);
Brian Silvermanb407c672014-04-09 11:58:37 -070080 if (__builtin_expect(!mock_time_enabled, 0)) {
Austin Schuhd78ab542013-03-01 22:22:19 -080081 LOG(FATAL, "Tried to set mock time and mock time is not enabled\n");
82 }
83 current_mock_time = now;
84}
85
Austin Schuh6a6f90c2016-11-25 21:36:42 -080086void IncrementMockTime(monotonic_clock::duration amount) {
Brian Silverman6659bc32013-10-16 10:31:32 -070087 static ::aos::Mutex mutex;
88 ::aos::MutexLocker sync(&mutex);
Austin Schuh6a6f90c2016-11-25 21:36:42 -080089 SetMockTime(monotonic_clock::now() + amount);
Brian Silverman6659bc32013-10-16 10:31:32 -070090}
91
Austin Schuhf2a50ba2016-12-24 16:16:26 -080092void OffsetToNow(monotonic_clock::time_point now) {
Brian Silverman0c715e62015-10-24 16:49:46 -040093 CHECK_NOTNULL(&global_core);
Brian Silvermand0575692015-02-21 16:24:02 -050094 CHECK_NOTNULL(global_core);
Brian Silverman0c715e62015-10-24 16:49:46 -040095 CHECK_NOTNULL(global_core->mem_struct);
Austin Schuhf2a50ba2016-12-24 16:16:26 -080096 const auto offset = now - monotonic_clock::now();
97 global_core->mem_struct->time_offset =
98 chrono::duration_cast<chrono::nanoseconds>(offset).count();
Brian Silvermand0575692015-02-21 16:24:02 -050099}
100
Neil Balch229001a2018-01-07 18:22:52 -0800101struct timespec to_timespec(
102 const ::aos::monotonic_clock::duration duration) {
103 struct timespec time_timespec;
104 ::std::chrono::seconds sec =
105 ::std::chrono::duration_cast<::std::chrono::seconds>(duration);
106 ::std::chrono::nanoseconds nsec =
107 ::std::chrono::duration_cast<::std::chrono::nanoseconds>(duration - sec);
108 time_timespec.tv_sec = sec.count();
109 time_timespec.tv_nsec = nsec.count();
110 return time_timespec;
111}
112
113struct timespec to_timespec(
114 const ::aos::monotonic_clock::time_point time) {
115 return to_timespec(time.time_since_epoch());
116}
brians343bc112013-02-10 01:53:46 +0000117} // namespace time
Austin Schuh858c0212016-11-25 17:23:30 -0800118
119constexpr monotonic_clock::time_point monotonic_clock::min_time;
120
121monotonic_clock::time_point monotonic_clock::now() noexcept {
122 {
123 if (time::mock_time_enabled.load(::std::memory_order_relaxed)) {
124 MutexLocker time_mutex_locker(&time::time_mutex);
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800125 return time::current_mock_time;
Austin Schuh858c0212016-11-25 17:23:30 -0800126 }
127 }
128
129 struct timespec current_time;
130 if (clock_gettime(CLOCK_MONOTONIC, &current_time) != 0) {
131 PLOG(FATAL, "clock_gettime(%jd, %p) failed",
132 static_cast<uintmax_t>(CLOCK_MONOTONIC), &current_time);
133 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800134 const chrono::nanoseconds offset =
135 (&global_core == nullptr || global_core == nullptr ||
136 global_core->mem_struct == nullptr)
137 ? chrono::nanoseconds(0)
138 : chrono::nanoseconds(global_core->mem_struct->time_offset);
139
Austin Schuh858c0212016-11-25 17:23:30 -0800140 return time_point(::std::chrono::seconds(current_time.tv_sec) +
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800141 ::std::chrono::nanoseconds(current_time.tv_nsec)) + offset;
Austin Schuh858c0212016-11-25 17:23:30 -0800142}
143
144
brians343bc112013-02-10 01:53:46 +0000145} // namespace aos