1 /*
2  * Copyright (C) 2005-2017 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 
17 #pragma once
18 
19 #include <stdint.h>
20 #include <time.h>
21 
22 /* struct log_time is a wire-format variant of struct timespec */
23 #define NS_PER_SEC 1000000000ULL
24 #define US_PER_SEC 1000000ULL
25 #define MS_PER_SEC 1000ULL
26 
27 #define LOG_TIME_SEC(t) ((t)->tv_sec)
28 /* next power of two after NS_PER_SEC */
29 #define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2))
30 
31 #ifdef __cplusplus
32 
33 extern "C" {
34 
35 struct log_time {
36  public:
37   uint32_t tv_sec = 0; /* good to Feb 5 2106 */
38   uint32_t tv_nsec = 0;
39 
40   static constexpr timespec EPOCH = {0, 0};
41 
log_timelog_time42   log_time() {}
log_timelog_time43   explicit log_time(const timespec& T)
44       : tv_sec(static_cast<uint32_t>(T.tv_sec)), tv_nsec(static_cast<uint32_t>(T.tv_nsec)) {}
45   explicit log_time(uint32_t sec, uint32_t nsec = 0)
tv_seclog_time46       : tv_sec(sec), tv_nsec(nsec) {
47   }
48 #ifdef __linux__
log_timelog_time49   explicit log_time(clockid_t id) {
50     timespec T;
51     clock_gettime(id, &T);
52     tv_sec = static_cast<uint32_t>(T.tv_sec);
53     tv_nsec = static_cast<uint32_t>(T.tv_nsec);
54   }
55 #endif
56   /* timespec */
57   bool operator==(const timespec& T) const {
58     return (tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
59            (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
60   }
61   bool operator!=(const timespec& T) const {
62     return !(*this == T);
63   }
64   bool operator<(const timespec& T) const {
65     return (tv_sec < static_cast<uint32_t>(T.tv_sec)) ||
66            ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
67             (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
68   }
69   bool operator>=(const timespec& T) const {
70     return !(*this < T);
71   }
72   bool operator>(const timespec& T) const {
73     return (tv_sec > static_cast<uint32_t>(T.tv_sec)) ||
74            ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
75             (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
76   }
77   bool operator<=(const timespec& T) const {
78     return !(*this > T);
79   }
80 
81   /* log_time */
82   bool operator==(const log_time& T) const {
83     return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
84   }
85   bool operator!=(const log_time& T) const {
86     return !(*this == T);
87   }
88   bool operator<(const log_time& T) const {
89     return (tv_sec < T.tv_sec) ||
90            ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
91   }
92   bool operator>=(const log_time& T) const {
93     return !(*this < T);
94   }
95   bool operator>(const log_time& T) const {
96     return (tv_sec > T.tv_sec) ||
97            ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
98   }
99   bool operator<=(const log_time& T) const {
100     return !(*this > T);
101   }
102 
103   log_time operator-=(const log_time& T) {
104     // No concept of negative time, clamp to EPOCH
105     if (*this <= T) {
106       return *this = log_time(EPOCH);
107     }
108 
109     if (this->tv_nsec < T.tv_nsec) {
110       --this->tv_sec;
111       this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
112     } else {
113       this->tv_nsec -= T.tv_nsec;
114     }
115     this->tv_sec -= T.tv_sec;
116 
117     return *this;
118   }
119   log_time operator-(const log_time& T) const {
120     log_time local(*this);
121     return local -= T;
122   }
123   log_time operator+=(const log_time& T) {
124     this->tv_nsec += T.tv_nsec;
125     if (this->tv_nsec >= NS_PER_SEC) {
126       this->tv_nsec -= NS_PER_SEC;
127       ++this->tv_sec;
128     }
129     this->tv_sec += T.tv_sec;
130 
131     return *this;
132   }
133   log_time operator+(const log_time& T) const {
134     log_time local(*this);
135     return local += T;
136   }
137 
nseclog_time138   uint64_t nsec() const {
139     return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
140   }
useclog_time141   uint64_t usec() const {
142     return static_cast<uint64_t>(tv_sec) * US_PER_SEC +
143            tv_nsec / (NS_PER_SEC / US_PER_SEC);
144   }
mseclog_time145   uint64_t msec() const {
146     return static_cast<uint64_t>(tv_sec) * MS_PER_SEC +
147            tv_nsec / (NS_PER_SEC / MS_PER_SEC);
148   }
149 
150   /* Add %#q for the fraction of a second to the standard library functions */
151   char* strptime(const char* s, const char* format);
152 } __attribute__((__packed__));
153 }
154 
155 #else /* __cplusplus */
156 
157 typedef struct log_time {
158   uint32_t tv_sec;
159   uint32_t tv_nsec;
160 } __attribute__((__packed__)) log_time;
161 
162 #endif /* __cplusplus */
163