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