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