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
21namespace cvd {
22namespace time {
23
24static const int64_t kNanosecondsPerSecond = 1000000000;
25
26class TimeDifference {
27 public:
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
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
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
90  int64_t count() const {
91    return ts_.tv_sec * (kNanosecondsPerSecond / scale_) + ts_.tv_nsec / scale_;
92  }
93
94  time_t seconds() const {
95    return ts_.tv_sec;
96  }
97
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
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
119class MonotonicTimePoint {
120 public:
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
139  MonotonicTimePoint() {
140    ts_.tv_sec = 0;
141    ts_.tv_nsec = 0;
142  }
143
144  explicit MonotonicTimePoint(const struct timespec& ts) {
145    ts_ = ts;
146  }
147
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
221  void ToTimespec(struct timespec* dest) const {
222    *dest = ts_;
223  }
224
225 protected:
226  struct timespec ts_;
227};
228
229class MonotonicTimePointFactory {
230 public:
231  static MonotonicTimePointFactory* GetInstance();
232
233  virtual ~MonotonicTimePointFactory() { }
234
235  virtual void FetchCurrentTime(MonotonicTimePoint* dest) const {
236    *dest = MonotonicTimePoint::Now();
237  }
238};
239
240class Seconds : public TimeDifference {
241 public:
242  explicit Seconds(const TimeDifference& difference) :
243      TimeDifference(difference, kNanosecondsPerSecond) { }
244
245  Seconds(int64_t seconds) :
246      TimeDifference(seconds, 0, kNanosecondsPerSecond) { }
247};
248
249class Milliseconds : public TimeDifference {
250 public:
251  explicit Milliseconds(const TimeDifference& difference) :
252      TimeDifference(difference, kScale) { }
253
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
261class Microseconds : public TimeDifference {
262 public:
263  explicit Microseconds(const TimeDifference& difference) :
264      TimeDifference(difference, kScale) { }
265
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
273class Nanoseconds : public TimeDifference {
274 public:
275  explicit Nanoseconds(const TimeDifference& difference) :
276      TimeDifference(difference, 1) { }
277  Nanoseconds(int64_t ns) : TimeDifference(ns / kNanosecondsPerSecond,
278                                           ns % kNanosecondsPerSecond, 1) { }
279};
280
281}  // namespace time
282}  // namespace cvd
283
284/**
285 * Legacy support for microseconds. Use MonotonicTimePoint in new code.
286 */
287static const int64_t kSecsToUsecs = static_cast<int64_t>(1000) * 1000;
288
289static inline int64_t get_monotonic_usecs() {
290  return cvd::time::Microseconds(
291      cvd::time::MonotonicTimePoint::Now().SinceEpoch()).count();
292}
293