blob: 0333c5c5e1c8082c8548fc6bbbb9ba5fabb95115 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_TIME_H_
2#define AOS_TIME_H_
brians343bc112013-02-10 01:53:46 +00003
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>
Austin Schuh793d6b92016-05-01 13:28:14 -070010#include <chrono>
11#include <thread>
brians343bc112013-02-10 01:53:46 +000012#include <ostream>
13
John Park33858a32018-09-28 23:05:48 -070014#include "aos/type_traits/type_traits.h"
15#include "aos/macros.h"
brians343bc112013-02-10 01:53:46 +000016
17namespace aos {
Austin Schuh793d6b92016-05-01 13:28:14 -070018
19class monotonic_clock {
20 public:
21 typedef ::std::chrono::nanoseconds::rep rep;
22 typedef ::std::chrono::nanoseconds::period period;
23 typedef ::std::chrono::nanoseconds duration;
24 typedef ::std::chrono::time_point<monotonic_clock> time_point;
25
26 static monotonic_clock::time_point now() noexcept;
Brian Silvermana3688802019-02-16 19:31:26 -080027 // This clock is still subject to rate adjustments based on adjtime, so it is
28 // not steady.
29 static constexpr bool is_steady = false;
30
31 // Returns the epoch (0).
32 static constexpr monotonic_clock::time_point epoch() {
33 return time_point(zero());
34 }
35
36 static constexpr monotonic_clock::duration zero() { return duration(0); }
37
38 static constexpr time_point min_time{
39 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080040 static constexpr time_point max_time{
41 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Brian Silvermana3688802019-02-16 19:31:26 -080042};
43
44class realtime_clock {
45 public:
46 typedef ::std::chrono::nanoseconds::rep rep;
47 typedef ::std::chrono::nanoseconds::period period;
48 typedef ::std::chrono::nanoseconds duration;
49 typedef ::std::chrono::time_point<monotonic_clock> time_point;
50
51#ifdef __linux__
52 static monotonic_clock::time_point now() noexcept;
53#endif // __linux__
54 static constexpr bool is_steady = false;
Austin Schuh793d6b92016-05-01 13:28:14 -070055
56 // Returns the epoch (0).
57 static constexpr monotonic_clock::time_point epoch() {
Austin Schuh8aec1ed2016-05-01 13:29:20 -070058 return time_point(zero());
Austin Schuh793d6b92016-05-01 13:28:14 -070059 }
Austin Schuh8aec1ed2016-05-01 13:29:20 -070060
61 static constexpr monotonic_clock::duration zero() { return duration(0); }
Austin Schuh858c0212016-11-25 17:23:30 -080062
63 static constexpr time_point min_time{
64 time_point(duration(::std::numeric_limits<duration::rep>::min()))};
Brian Silverman94357272019-02-23 21:00:54 -080065 static constexpr time_point max_time{
66 time_point(duration(::std::numeric_limits<duration::rep>::max()))};
Austin Schuh793d6b92016-05-01 13:28:14 -070067};
68
brians343bc112013-02-10 01:53:46 +000069namespace time {
70
Brian Silvermanc03a30c2019-02-16 18:21:56 -080071#ifdef __linux__
72
Austin Schuh6a6f90c2016-11-25 21:36:42 -080073// Enables returning the mock time value for Now instead of checking the system
74// clock.
75void EnableMockTime(monotonic_clock::time_point now);
76// Calls SetMockTime with the current actual time.
77void UpdateMockTime();
78// Sets now when time is being mocked.
79void SetMockTime(monotonic_clock::time_point now);
80// Convenience function to just increment the mock time by a certain amount in
81// a thread safe way.
82void IncrementMockTime(monotonic_clock::duration amount);
83// Disables mocking time.
84void DisableMockTime();
85
Austin Schuhf2a50ba2016-12-24 16:16:26 -080086// Sets the global offset for all times so monotonic_clock::now() will return
Brian Silvermand0575692015-02-21 16:24:02 -050087// now.
88// There is no synchronization here, so this is only safe when only a single
89// task is running.
90// This is only allowed when the shared memory core infrastructure has been
91// initialized in this process.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080092void OffsetToNow(const monotonic_clock::time_point now);
Brian Silvermand0575692015-02-21 16:24:02 -050093
Austin Schuhf2a50ba2016-12-24 16:16:26 -080094// Construct a time representing the period of hertz.
95constexpr ::std::chrono::nanoseconds FromRate(int hertz) {
96 return ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
97 ::std::chrono::seconds(1)) /
98 hertz;
99}
100
101// RAII class that freezes monotonic_clock::now() (to avoid making large numbers
102// of syscalls to find the real time).
Brian Silvermanb407c672014-04-09 11:58:37 -0700103class TimeFreezer {
104 public:
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800105 TimeFreezer() { EnableMockTime(monotonic_clock::now()); }
106 ~TimeFreezer() { DisableMockTime(); }
Brian Silvermanb407c672014-04-09 11:58:37 -0700107
108 private:
109 DISALLOW_COPY_AND_ASSIGN(TimeFreezer);
110};
111
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800112#endif // __linux__
113
Neil Balch229001a2018-01-07 18:22:52 -0800114// Converts a monotonic_clock::duration into a timespec object.
115struct timespec to_timespec(::aos::monotonic_clock::duration duration);
116
117// Converts a monotonic_clock::time_point into a timespec object as time since
118// epoch.
119struct timespec to_timespec(::aos::monotonic_clock::time_point time);
120
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800121namespace time_internal {
122
123template <class T>
124struct is_duration : std::false_type {};
125template <class Rep, class Period>
126struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
127
128} // namespace time_internal
129
130// Returns the greatest duration t representable in ToDuration that is less or
131// equal to d.
132// Implementation copied from
133// https://en.cppreference.com/w/cpp/chrono/duration/floor.
134// TODO(Brian): Remove once we have C++17 support.
135template <class To, class Rep, class Period,
136 class = std::enable_if_t<time_internal::is_duration<To>{}>>
137constexpr To floor(const std::chrono::duration<Rep, Period> &d) {
138 To t = std::chrono::duration_cast<To>(d);
139 if (t > d) return t - To{1};
140 return t;
141}
142
143// Returns the value t representable in ToDuration that is the closest to d. If
144// there are two such values, returns the even value (that is, the value t such
145// that t % 2 == 0).
146// Implementation copied from
147// https://en.cppreference.com/w/cpp/chrono/duration/round.
148// TODO(Brian): Remove once we have C++17 support.
149template <class To, class Rep, class Period,
150 class = std::enable_if_t<
151 time_internal::is_duration<To>{} &&
152 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
153constexpr To round(const std::chrono::duration<Rep, Period> &d) {
154 To t0 = aos::time::floor<To>(d);
155 To t1 = t0 + To{1};
156 auto diff0 = d - t0;
157 auto diff1 = t1 - d;
158 if (diff0 == diff1) {
159 if (t0.count() & 1) return t1;
160 return t0;
161 } else if (diff0 < diff1) {
162 return t0;
163 }
164 return t1;
165}
166
167// Returns the nearest time point to tp representable in ToDuration, rounding to
168// even in halfway cases, like std::chrono::round in C++17.
169// Implementation copied from
170// https://en.cppreference.com/w/cpp/chrono/time_point/round.
171// TODO(Brian): Remove once we have C++17 support.
172template <class To, class Clock, class FromDuration,
173 class = std::enable_if_t<
174 time_internal::is_duration<To>{} &&
175 !std::chrono::treat_as_floating_point<typename To::rep>{}>>
176constexpr std::chrono::time_point<Clock, To> round(
177 const std::chrono::time_point<Clock, FromDuration> &tp) {
178 return std::chrono::time_point<Clock, To>{
179 aos::time::round<To>(tp.time_since_epoch())};
180}
181
brians343bc112013-02-10 01:53:46 +0000182} // namespace time
183} // namespace aos
184
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800185#ifdef __linux__
186
Austin Schuh793d6b92016-05-01 13:28:14 -0700187namespace std {
188namespace this_thread {
189// Template specialization for monotonic_clock, since we can use clock_nanosleep
190// with TIMER_ABSTIME and get very precise absolute time sleeps.
191template <>
192void sleep_until(const ::aos::monotonic_clock::time_point &end_time);
193
194} // namespace this_thread
195} // namespace std
196
Brian Silvermanc03a30c2019-02-16 18:21:56 -0800197#endif // __linux__
Austin Schuh793d6b92016-05-01 13:28:14 -0700198
John Park33858a32018-09-28 23:05:48 -0700199#endif // AOS_TIME_H_