1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include <stdint.h>
19 #include <time.h>
20
21 namespace cuttlefish {
22 namespace time {
23
24 static const int64_t kNanosecondsPerSecond = 1000000000;
25
26 class TimeDifference {
27 public:
TimeDifference(time_t seconds,long nanoseconds,int64_t scale)28 TimeDifference(time_t seconds, long nanoseconds, int64_t scale) :
29 scale_(scale), truncated_(false) {
30 ts_.tv_sec = seconds;
31 ts_.tv_nsec = nanoseconds;
32 if (scale_ == kNanosecondsPerSecond) {
33 truncated_ = true;
34 truncated_ns_ = 0;
35 }
36 }
37
TimeDifference(const TimeDifference & in,int64_t scale)38 TimeDifference(const TimeDifference& in, int64_t scale) :
39 scale_(scale), truncated_(false) {
40 ts_ = in.GetTS();
41 if (scale_ == kNanosecondsPerSecond) {
42 truncated_ = true;
43 truncated_ns_ = 0;
44 } else if ((in.scale_ % scale_) == 0) {
45 truncated_ = true;
46 truncated_ns_ = ts_.tv_nsec;
47 }
48 }
49
TimeDifference(const struct timespec & in,int64_t scale)50 TimeDifference(const struct timespec& in, int64_t scale) :
51 ts_(in), scale_(scale), truncated_(false) { }
52
53 TimeDifference operator*(const uint32_t factor) {
54 TimeDifference rval = *this;
55 rval.ts_.tv_sec = ts_.tv_sec * factor;
56 // Create temporary variable to hold the multiplied
57 // nanoseconds so that no overflow is possible.
58 // Nanoseconds must be in [0, 10^9) and so all are less
59 // then 2^30. Even multiplied by the largest uint32
60 // this will fit in a 64-bit int without overflow.
61 int64_t tv_nsec = static_cast<int64_t>(ts_.tv_nsec) * factor;
62 rval.ts_.tv_sec += (tv_nsec / kNanosecondsPerSecond);
63 rval.ts_.tv_nsec = tv_nsec % kNanosecondsPerSecond;
64 return rval;
65 }
66
67 TimeDifference operator+(const TimeDifference& other) const {
68 struct timespec ret = ts_;
69 ret.tv_nsec = (ts_.tv_nsec + other.ts_.tv_nsec) % 1000000000;
70 ret.tv_sec = (ts_.tv_sec + other.ts_.tv_sec) +
71 (ts_.tv_nsec + other.ts_.tv_nsec) / 1000000000;
72 return TimeDifference(ret, scale_ < other.scale_ ? scale_: other.scale_);
73 }
74
75 TimeDifference operator-(const TimeDifference& other) const {
76 struct timespec ret = ts_;
77 // Keeps nanoseconds positive and allow negative numbers only on
78 // seconds.
79 ret.tv_nsec = (1000000000 + ts_.tv_nsec - other.ts_.tv_nsec) % 1000000000;
80 ret.tv_sec = (ts_.tv_sec - other.ts_.tv_sec) -
81 (ts_.tv_nsec < other.ts_.tv_nsec ? 1 : 0);
82 return TimeDifference(ret, scale_ < other.scale_ ? scale_: other.scale_);
83 }
84
85 bool operator<(const TimeDifference& other) const {
86 return ts_.tv_sec < other.ts_.tv_sec ||
87 (ts_.tv_sec == other.ts_.tv_sec && ts_.tv_nsec < other.ts_.tv_nsec);
88 }
89
count()90 int64_t count() const {
91 return ts_.tv_sec * (kNanosecondsPerSecond / scale_) + ts_.tv_nsec / scale_;
92 }
93
seconds()94 time_t seconds() const {
95 return ts_.tv_sec;
96 }
97
subseconds_in_ns()98 long subseconds_in_ns() const {
99 if (!truncated_) {
100 truncated_ns_ = (ts_.tv_nsec / scale_) * scale_;
101 truncated_ = true;
102 }
103 return truncated_ns_;
104 }
105
GetTS()106 struct timespec GetTS() const {
107 // We can't assume C++11, so avoid extended initializer lists.
108 struct timespec rval = { ts_.tv_sec, subseconds_in_ns()};
109 return rval;
110 }
111
112 protected:
113 struct timespec ts_;
114 int64_t scale_;
115 mutable bool truncated_;
116 mutable long truncated_ns_;
117 };
118
119 class MonotonicTimePoint {
120 public:
Now()121 static MonotonicTimePoint Now() {
122 struct timespec ts;
123 #ifdef CLOCK_MONOTONIC_RAW
124 // WARNING:
125 // While we do have CLOCK_MONOTONIC_RAW, we can't depend on it until:
126 // - ALL places relying on MonotonicTimePoint are fixed,
127 // - pthread supports pthread_timewait_monotonic.
128 //
129 // This is currently observable as a LEGITIMATE problem while running
130 // pthread_test. DO NOT revert this to CLOCK_MONOTONIC_RAW until test
131 // passes.
132 clock_gettime(CLOCK_MONOTONIC, &ts);
133 #else
134 clock_gettime(CLOCK_MONOTONIC, &ts);
135 #endif
136 return MonotonicTimePoint(ts);
137 }
138
MonotonicTimePoint()139 MonotonicTimePoint() {
140 ts_.tv_sec = 0;
141 ts_.tv_nsec = 0;
142 }
143
MonotonicTimePoint(const struct timespec & ts)144 explicit MonotonicTimePoint(const struct timespec& ts) {
145 ts_ = ts;
146 }
147
SinceEpoch()148 TimeDifference SinceEpoch() const {
149 return TimeDifference(ts_, 1);
150 }
151
152 TimeDifference operator-(const MonotonicTimePoint& other) const {
153 struct timespec rval;
154 rval.tv_sec = ts_.tv_sec - other.ts_.tv_sec;
155 rval.tv_nsec = ts_.tv_nsec - other.ts_.tv_nsec;
156 if (rval.tv_nsec < 0) {
157 --rval.tv_sec;
158 rval.tv_nsec += kNanosecondsPerSecond;
159 }
160 return TimeDifference(rval, 1);
161 }
162
163 MonotonicTimePoint operator+(const TimeDifference& other) const {
164 MonotonicTimePoint rval = *this;
165 rval.ts_.tv_sec += other.seconds();
166 rval.ts_.tv_nsec += other.subseconds_in_ns();
167 if (rval.ts_.tv_nsec >= kNanosecondsPerSecond) {
168 ++rval.ts_.tv_sec;
169 rval.ts_.tv_nsec -= kNanosecondsPerSecond;
170 }
171 return rval;
172 }
173
174 bool operator==(const MonotonicTimePoint& other) const {
175 return (ts_.tv_sec == other.ts_.tv_sec) &&
176 (ts_.tv_nsec == other.ts_.tv_nsec);
177 }
178
179 bool operator!=(const MonotonicTimePoint& other) const {
180 return !(*this == other);
181 }
182
183 bool operator<(const MonotonicTimePoint& other) const {
184 return ((ts_.tv_sec - other.ts_.tv_sec) < 0) ||
185 ((ts_.tv_sec == other.ts_.tv_sec) &&
186 (ts_.tv_nsec < other.ts_.tv_nsec));
187 }
188
189 bool operator>(const MonotonicTimePoint& other) const {
190 return other < *this;
191 }
192
193 bool operator<=(const MonotonicTimePoint& other) const {
194 return !(*this > other);
195 }
196
197 bool operator>=(const MonotonicTimePoint& other) const {
198 return !(*this < other);
199 }
200
201 MonotonicTimePoint& operator+=(const TimeDifference& other) {
202 ts_.tv_sec += other.seconds();
203 ts_.tv_nsec += other.subseconds_in_ns();
204 if (ts_.tv_nsec >= kNanosecondsPerSecond) {
205 ++ts_.tv_sec;
206 ts_.tv_nsec -= kNanosecondsPerSecond;
207 }
208 return *this;
209 }
210
211 MonotonicTimePoint& operator-=(const TimeDifference& other) {
212 ts_.tv_sec -= other.seconds();
213 ts_.tv_nsec -= other.subseconds_in_ns();
214 if (ts_.tv_nsec < 0) {
215 --ts_.tv_sec;
216 ts_.tv_nsec += kNanosecondsPerSecond;
217 }
218 return *this;
219 }
220
ToTimespec(struct timespec * dest)221 void ToTimespec(struct timespec* dest) const {
222 *dest = ts_;
223 }
224
225 protected:
226 struct timespec ts_;
227 };
228
229 class MonotonicTimePointFactory {
230 public:
231 static MonotonicTimePointFactory* GetInstance();
232
~MonotonicTimePointFactory()233 virtual ~MonotonicTimePointFactory() { }
234
FetchCurrentTime(MonotonicTimePoint * dest)235 virtual void FetchCurrentTime(MonotonicTimePoint* dest) const {
236 *dest = MonotonicTimePoint::Now();
237 }
238 };
239
240 class Seconds : public TimeDifference {
241 public:
Seconds(const TimeDifference & difference)242 explicit Seconds(const TimeDifference& difference) :
243 TimeDifference(difference, kNanosecondsPerSecond) { }
244
Seconds(int64_t seconds)245 Seconds(int64_t seconds) :
246 TimeDifference(seconds, 0, kNanosecondsPerSecond) { }
247 };
248
249 class Milliseconds : public TimeDifference {
250 public:
Milliseconds(const TimeDifference & difference)251 explicit Milliseconds(const TimeDifference& difference) :
252 TimeDifference(difference, kScale) { }
253
Milliseconds(int64_t ms)254 Milliseconds(int64_t ms) : TimeDifference(
255 ms / 1000, (ms % 1000) * kScale, kScale) { }
256
257 protected:
258 static const int kScale = kNanosecondsPerSecond / 1000;
259 };
260
261 class Microseconds : public TimeDifference {
262 public:
Microseconds(const TimeDifference & difference)263 explicit Microseconds(const TimeDifference& difference) :
264 TimeDifference(difference, kScale) { }
265
Microseconds(int64_t micros)266 Microseconds(int64_t micros) : TimeDifference(
267 micros / 1000000, (micros % 1000000) * kScale, kScale) { }
268
269 protected:
270 static const int kScale = kNanosecondsPerSecond / 1000000;
271 };
272
273 class Nanoseconds : public TimeDifference {
274 public:
Nanoseconds(const TimeDifference & difference)275 explicit Nanoseconds(const TimeDifference& difference) :
276 TimeDifference(difference, 1) { }
Nanoseconds(int64_t ns)277 Nanoseconds(int64_t ns) : TimeDifference(ns / kNanosecondsPerSecond,
278 ns % kNanosecondsPerSecond, 1) { }
279 };
280
281 } // namespace time
282 } // namespace cuttlefish
283
284 /**
285 * Legacy support for microseconds. Use MonotonicTimePoint in new code.
286 */
287 static const int64_t kSecsToUsecs = static_cast<int64_t>(1000) * 1000;
288
get_monotonic_usecs()289 static inline int64_t get_monotonic_usecs() {
290 return cuttlefish::time::Microseconds(
291 cuttlefish::time::MonotonicTimePoint::Now().SinceEpoch()).count();
292 }
293