implement timeouts for events

Change-Id: I8ec89fc5bdc7b53ddc1d5c86494615c95be9bd0e
diff --git a/aos/common/BUILD b/aos/common/BUILD
index 45c1d72..4262b60 100644
--- a/aos/common/BUILD
+++ b/aos/common/BUILD
@@ -96,6 +96,7 @@
   ],
   deps = [
     '//aos/linux_code/ipc_lib:aos_sync',
+    ':time',
   ],
 )
 
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 9c43936..14619ad 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -253,10 +253,12 @@
       ],
       'dependencies': [
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:aos_sync',
+        'time',
         '<(AOS)/build/aos.gyp:logging_interface',
       ],
       'export_dependent_settings': [
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:aos_sync',
+        'time',
       ],
     },
     {
diff --git a/aos/common/event.h b/aos/common/event.h
index 9839d41..b3ee87b 100644
--- a/aos/common/event.h
+++ b/aos/common/event.h
@@ -1,6 +1,8 @@
 #ifndef AOS_COMMON_EVENT_H_
 #define AOS_COMMON_EVENT_H_
 
+#include "aos/common/time.h"
+
 #include "aos/linux_code/ipc_lib/aos_sync.h"
 
 namespace aos {
@@ -37,6 +39,11 @@
   // Waits for the event to be set. Returns immediately if it is already set.
   void Wait();
 
+  // Waits for the event to be set or until timeout has elapsed. Returns
+  // immediately if it is already set.
+  // Returns true if the event was Set or false if the timeout expired.
+  bool WaitTimeout(const ::aos::time::Time &timeout);
+
   // Wakes up all Wait()ers and sets the event (atomically).
   void Set();
   // Unsets the event so future Wait() callers will block instead of returning
diff --git a/aos/common/event_test.cc b/aos/common/event_test.cc
index d8671eb..7331309 100644
--- a/aos/common/event_test.cc
+++ b/aos/common/event_test.cc
@@ -12,7 +12,7 @@
 
 class EventTest : public ::testing::Test {
  public:
-  Event test_event;
+  Event test_event_;
 
  protected:
   void SetUp() override {
@@ -22,13 +22,13 @@
 
 // Makes sure that basic operations with no blocking or anything work.
 TEST_F(EventTest, Basic) {
-  EXPECT_FALSE(test_event.Clear());
-  EXPECT_FALSE(test_event.Clear());
+  EXPECT_FALSE(test_event_.Clear());
+  EXPECT_FALSE(test_event_.Clear());
 
-  test_event.Set();
-  test_event.Wait();
-  EXPECT_TRUE(test_event.Clear());
-  EXPECT_FALSE(test_event.Clear());
+  test_event_.Set();
+  test_event_.Wait();
+  EXPECT_TRUE(test_event_.Clear());
+  EXPECT_FALSE(test_event_.Clear());
 }
 
 // Tests that tsan understands that events establish a happens-before
@@ -36,13 +36,13 @@
 TEST_F(EventTest, ThreadSanitizer) {
   for (int i = 0; i < 3000; ++i) {
     int variable = 0;
-    test_event.Clear();
+    test_event_.Clear();
     ::std::thread thread([this, &variable]() {
-      test_event.Wait();
+      test_event_.Wait();
       --variable;
     });
     ++variable;
-    test_event.Set();
+    test_event_.Set();
     thread.join();
     EXPECT_EQ(0, variable);
   }
@@ -56,13 +56,33 @@
   ::std::thread thread([this, &start_time, &finish_time, &started]() {
     start_time = time::Time::Now();
     started.Set();
-    test_event.Wait();
+    test_event_.Wait();
     finish_time = time::Time::Now();
   });
   static const time::Time kWaitTime = time::Time::InSeconds(0.05);
   started.Wait();
   time::SleepFor(kWaitTime);
-  test_event.Set();
+  test_event_.Set();
+  thread.join();
+  EXPECT_GE(finish_time - start_time, kWaitTime);
+}
+
+TEST_F(EventTest, WaitTimeout) {
+  EXPECT_FALSE(test_event_.WaitTimeout(time::Time::InSeconds(0.05)));
+
+  time::Time start_time, finish_time;
+  // Without this, it sometimes manages to fail under tsan.
+  Event started;
+  ::std::thread thread([this, &start_time, &finish_time, &started]() {
+    start_time = time::Time::Now();
+    started.Set();
+    EXPECT_TRUE(test_event_.WaitTimeout(time::Time::InSeconds(0.5)));
+    finish_time = time::Time::Now();
+  });
+  static const time::Time kWaitTime = time::Time::InSeconds(0.05);
+  started.Wait();
+  time::SleepFor(kWaitTime);
+  test_event_.Set();
   thread.join();
   EXPECT_GE(finish_time - start_time, kWaitTime);
 }