Added monotonic_clock class in time.h

Change-Id: Iea80a7cde09a985f7fbf64090c58aeccde38e949
diff --git a/aos/common/time.cc b/aos/common/time.cc
index 87c991d..125b016 100644
--- a/aos/common/time.cc
+++ b/aos/common/time.cc
@@ -12,7 +12,45 @@
 #include "aos/common/logging/logging.h"
 #include "aos/common/mutex.h"
 
+namespace std {
+namespace this_thread {
+template <>
+void sleep_until(const ::aos::monotonic_clock::time_point &end_time) {
+  struct timespec end_time_timespec;
+  ::std::chrono::seconds sec =
+      ::std::chrono::duration_cast<::std::chrono::seconds>(
+          end_time.time_since_epoch());
+  ::std::chrono::nanoseconds nsec =
+      ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
+          end_time.time_since_epoch() - sec);
+  end_time_timespec.tv_sec = sec.count();
+  end_time_timespec.tv_nsec = nsec.count();
+  int returnval;
+  do {
+    returnval = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
+                                &end_time_timespec, nullptr);
+    if (returnval != EINTR && returnval != 0) {
+      PLOG(FATAL, "clock_nanosleep(%jd, TIMER_ABSTIME, %p, nullptr) failed",
+           static_cast<uintmax_t>(CLOCK_MONOTONIC), &end_time_timespec);
+    }
+  } while (returnval != 0);
+}
+
+}  // namespace this_thread
+}  // namespace std
+
+
 namespace aos {
+monotonic_clock::time_point monotonic_clock::now() noexcept {
+  struct timespec current_time;
+  if (clock_gettime(CLOCK_MONOTONIC, &current_time) != 0) {
+    PLOG(FATAL, "clock_gettime(%jd, %p) failed",
+         static_cast<uintmax_t>(CLOCK_MONOTONIC), &current_time);
+  }
+  return time_point(::std::chrono::seconds(current_time.tv_sec) +
+                    ::std::chrono::nanoseconds(current_time.tv_nsec));
+}
+
 namespace time {
 
 // State required to enable and use mock time.
diff --git a/aos/common/time.h b/aos/common/time.h
index a176ba0..40b72b0 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -7,12 +7,31 @@
 #include <stdint.h>
 
 #include <type_traits>
+#include <chrono>
+#include <thread>
 #include <ostream>
 
 #include "aos/common/type_traits.h"
 #include "aos/common/macros.h"
 
 namespace aos {
+
+class monotonic_clock {
+ public:
+  typedef ::std::chrono::nanoseconds::rep rep;
+  typedef ::std::chrono::nanoseconds::period period;
+  typedef ::std::chrono::nanoseconds duration;
+  typedef ::std::chrono::time_point<monotonic_clock> time_point;
+
+  static monotonic_clock::time_point now() noexcept;
+  static constexpr bool is_steady = true;
+
+  // Returns the epoch (0).
+  static constexpr monotonic_clock::time_point epoch() {
+    return time_point(duration(0));
+  }
+};
+
 namespace time {
 
 // A nice structure for representing times.
@@ -280,4 +299,15 @@
 }  // namespace time
 }  // namespace aos
 
+namespace std {
+namespace this_thread {
+// Template specialization for monotonic_clock, since we can use clock_nanosleep
+// with TIMER_ABSTIME and get very precise absolute time sleeps.
+template <>
+void sleep_until(const ::aos::monotonic_clock::time_point &end_time);
+
+}  // namespace this_thread
+}  // namespace std
+
+
 #endif  // AOS_COMMON_TIME_H_
diff --git a/aos/common/time_test.cc b/aos/common/time_test.cc
index 008b3cf..3ae82ab 100644
--- a/aos/common/time_test.cc
+++ b/aos/common/time_test.cc
@@ -1,5 +1,7 @@
 #include "aos/common/time.h"
 
+#include <thread>
+
 #include "gtest/gtest.h"
 
 #include "aos/common/macros.h"
@@ -256,6 +258,16 @@
   EXPECT_EQ(MACRO_DARG(Time(0, Time::kNSecInSec / 100)), Time::FromRate(100));
 }
 
+// Test the monotonic_clock and sleep_until functions.
+TEST(TimeTest, MonotonicClockSleepAndNow) {
+  monotonic_clock::time_point start = monotonic_clock::now();
+  const auto kSleepTime = ::std::chrono::milliseconds(500);
+  ::std::this_thread::sleep_until(start + kSleepTime);
+  monotonic_clock::time_point end = monotonic_clock::now();
+  EXPECT_GE(end - start, kSleepTime);
+  EXPECT_LT(end - start, kSleepTime + ::std::chrono::milliseconds(200));
+}
+
 }  // namespace testing
 }  // namespace time
 }  // namespace aos