blob: 1d97b80882c4c8d8aec496094df1fe64aec44c75 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include "aos/common/time.h"
2
3#ifdef __VXWORKS__
4#include <taskLib.h>
5#endif
6
7#include "aos/common/logging/logging.h"
8#include "aos/common/inttypes.h"
9
10namespace aos {
11namespace time {
12
13Time Time::Now(clockid_t clock) {
14 timespec temp;
15 if (clock_gettime(clock, &temp) != 0) {
16 // TODO(aschuh): There needs to be a pluggable low level logging interface
17 // so we can break this dependency loop. This also would help during
18 // startup.
19 LOG(FATAL, "clock_gettime(%jd, %p) failed with %d: %s\n",
20 static_cast<uintmax_t>(clock), &temp, errno, strerror(errno));
21 }
22 return Time(temp);
23}
24void Time::Check() {
25 if (nsec_ >= kNSecInSec || nsec_ < 0) {
26 LOG(FATAL, "0 <= nsec_(%"PRId32") < %"PRId32" isn't true.\n",
27 nsec_, kNSecInSec);
28 }
29 static_assert(aos::shm_ok<Time>::value,
30 "it should be able to go through shared memory");
31}
32
33Time &Time::operator+=(const Time &rhs) {
34 sec_ += rhs.sec_;
35 nsec_ += rhs.nsec_;
36 if (nsec_ >= kNSecInSec) {
37 nsec_ -= kNSecInSec;
38 sec_ += 1;
39 }
40 return *this;
41}
42const Time Time::operator+(const Time &rhs) const {
43 return Time(*this) += rhs;
44}
45Time &Time::operator-=(const Time &rhs) {
46 sec_ -= rhs.sec_;
47 nsec_ -= rhs.nsec_;
48 if (nsec_ < 0) {
49 nsec_ += kNSecInSec;
50 sec_ -= 1;
51 }
52 return *this;
53}
54const Time Time::operator-(const Time &rhs) const {
55 return Time(*this) -= rhs;
56}
57Time &Time::operator*=(int32_t rhs) {
58 const int64_t temp = static_cast<int64_t>(nsec_) *
59 static_cast<int64_t>(rhs);
60 sec_ *= rhs; // better not overflow, or the result is just too big
61 nsec_ = temp % kNSecInSec;
62 sec_ += (temp - nsec_) / kNSecInSec;
63 return *this;
64}
65const Time Time::operator*(int32_t rhs) const {
66 return Time(*this) *= rhs;
67}
68Time &Time::operator/=(int32_t rhs) {
69 nsec_ = (sec_ % rhs) * (kNSecInSec / rhs) + nsec_ / rhs;
70 sec_ /= rhs;
71 return *this;
72}
73const Time Time::operator/(int32_t rhs) const {
74 return Time(*this) /= rhs;
75}
76Time &Time::operator%=(int32_t rhs) {
77 nsec_ = ToNSec() % rhs;
78 const int wraps = nsec_ / kNSecInSec;
79 sec_ = wraps;
80 nsec_ -= kNSecInSec * wraps;
81 return *this;
82}
83const Time Time::operator%(int32_t rhs) const {
84 return Time(*this) %= rhs;
85}
86
87bool Time::operator==(const Time &rhs) const {
88 return sec_ == rhs.sec_ && nsec_ == rhs.nsec_;
89}
90bool Time::operator!=(const Time &rhs) const {
91 return !(*this == rhs);
92}
93bool Time::operator<(const Time &rhs) const {
94 return sec_ < rhs.sec_ || (sec_ == rhs.sec_ && nsec_ < rhs.nsec_);
95}
96bool Time::operator>(const Time &rhs) const {
97 return sec_ > rhs.sec_ || (sec_ == rhs.sec_ && nsec_ > rhs.nsec_);
98}
99bool Time::operator<=(const Time &rhs) const {
100 return sec_ < rhs.sec_ || (sec_ == rhs.sec_ && nsec_ <= rhs.nsec_);
101}
102bool Time::operator>=(const Time &rhs) const {
103 return sec_ > rhs.sec_ || (sec_ == rhs.sec_ && nsec_ >= rhs.nsec_);
104}
105
106bool Time::IsWithin(const Time &other, int64_t amount) const {
107 const int64_t temp = ToNSec() - other.ToNSec();
108 return temp <= amount && temp >= -amount;
109}
110
111std::ostream &operator<<(std::ostream &os, const Time& time) {
112 return os << "Time{" << time.sec_ << "s, " << time.nsec_ << "ns}";
113}
114
115void SleepFor(const Time &time, clockid_t clock) {
116#ifdef __VXWORKS__
117 SleepUntil(Time::Now(clock) + time, clock);
118#else
119 timespec converted(time.ToTimespec()), remaining;
120 int failure = EINTR;
121 do {
122 // This checks whether the last time through the loop actually failed or got
123 // interrupted.
124 if (failure != EINTR) {
125 LOG(FATAL, "clock_nanosleep(%jd, 0, %p, %p) returned %d: %s\n",
126 static_cast<intmax_t>(clock), &converted, &remaining,
127 failure, strerror(failure));
128 }
129 failure = clock_nanosleep(clock, 0, &converted, &remaining);
130 memcpy(&converted, &remaining, sizeof(converted));
131 } while (failure != 0);
132#endif
133}
134
135void SleepUntil(const Time &time, clockid_t clock) {
136#ifdef __VXWORKS__
137 if (clock != CLOCK_REALTIME) {
138 LOG(FATAL, "vxworks only supports CLOCK_REALTIME\n");
139 }
140 // Vxworks nanosleep is definitely broken (fails horribly at doing remaining
141 // right), and I don't really want to know how else it's broken, so I'm using
142 // taskDelay instead because that's simpler.
143 // The +1 is because sleep functions are supposed to sleep for at least the
144 // requested amount, so we have to round up to the next clock tick.
145 while (taskDelay((time - Time::Now(clock)).ToTicks() + 1) != 0) {
146 if (errno != EINTR) {
147 LOG(FATAL, "taskDelay(some ticks) failed with %d: %s\n",
148 errno, strerror(errno));
149 }
150 }
151#else
152 timespec converted(time.ToTimespec());
153 int failure;
154 while ((failure = clock_nanosleep(clock, TIMER_ABSTIME,
155 &converted, NULL)) != 0) {
156 if (failure != EINTR) {
157 LOG(FATAL, "clock_nanosleep(%jd, TIMER_ABSTIME, %p, NULL)"
158 " returned %d: %s\n", static_cast<intmax_t>(clock), &converted,
159 failure, strerror(failure));
160 }
161 }
162#endif
163}
164
165} // namespace time
166} // namespace aos