Squashed 'third_party/allwpilib_2017/' content from commit 35ac87d

Change-Id: I7bb6f5556c30d3f5a092e68de0be9c710c60c9f4
git-subtree-dir: third_party/allwpilib_2017
git-subtree-split: 35ac87d6ff8b7f061c4f18c9ea316e5dccd4888a
diff --git a/wpilibcIntegrationTests/src/ConditionVariableTest.cpp b/wpilibcIntegrationTests/src/ConditionVariableTest.cpp
new file mode 100644
index 0000000..e4e12aa
--- /dev/null
+++ b/wpilibcIntegrationTests/src/ConditionVariableTest.cpp
@@ -0,0 +1,298 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2016-2017. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+#include "HAL/cpp/priority_condition_variable.h"
+#include "HAL/cpp/priority_mutex.h"
+#include "TestBench.h"
+#include "gtest/gtest.h"
+
+namespace wpilib {
+namespace testing {
+
+// Tests that the condition variable class which we wrote ourselves actually
+// does work.
+class ConditionVariableTest : public ::testing::Test {
+ protected:
+  typedef std::unique_lock<priority_mutex> priority_lock;
+
+  // Condition variable to test.
+  priority_condition_variable m_cond;
+
+  // Mutex to pass to condition variable when waiting.
+  priority_mutex m_mutex;
+
+  // flags for testing when threads are completed.
+  std::atomic<bool> m_done1{false}, m_done2{false};
+  // Threads to use for testing. We want multiple threads to ensure that it
+  // behaves correctly when multiple processes are waiting on a signal.
+  std::thread m_watcher1, m_watcher2;
+
+  // Information for when running with predicates.
+  std::atomic<bool> m_pred_var{false};
+
+  void ShortSleep(uint32_t time = 10) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(time));
+  }
+
+  // Start up the given threads with a wait function. The wait function should
+  // call some version of m_cond.wait and should take as an argument a reference
+  // to an std::atomic<bool> which it will set to true when it is ready to have
+  // join called on it.
+  template <class Function>
+  void StartThreads(Function wait) {
+    m_watcher1 = std::thread(wait, std::ref(m_done1));
+    m_watcher2 = std::thread(wait, std::ref(m_done2));
+
+    // Wait briefly to let the lock be unlocked.
+    ShortSleep();
+    bool locked = m_mutex.try_lock();
+    if (locked) m_mutex.unlock();
+    EXPECT_TRUE(locked) << "The condition variable failed to unlock the lock.";
+  }
+
+  void NotifyAll() { m_cond.notify_all(); }
+  void NotifyOne() { m_cond.notify_one(); }
+
+  // Test that all the threads are notified by a notify_all() call.
+  void NotifyAllTest() {
+    NotifyAll();
+    // Wait briefly to let the lock be re-locked.
+    ShortSleep();
+    EXPECT_TRUE(m_done1) << "watcher1 failed to be notified.";
+    EXPECT_TRUE(m_done2) << "watcher2 failed to be notified.";
+  }
+
+  // For use when testing predicates. First tries signalling the threads with
+  // the predicate set to false (and ensures that they do not activate) and then
+  // tests with the predicate set to true.
+  void PredicateTest() {
+    m_pred_var = false;
+    NotifyAll();
+    ShortSleep();
+    EXPECT_FALSE(m_done1) << "watcher1 didn't pay attention to its predicate.";
+    EXPECT_FALSE(m_done2) << "watcher2 didn't pay attention to its predicate.";
+    m_pred_var = true;
+    NotifyAllTest();
+  }
+
+  // Used by the WaitFor and WaitUntil tests to test that, without a predicate,
+  // the timeout works properly.
+  void WaitTimeTest(bool wait_for) {
+    std::atomic<bool> timed_out{true};
+    auto wait_until = [this, &timed_out, wait_for](std::atomic<bool>& done) {
+      priority_lock lock(m_mutex);
+      done = false;
+      if (wait_for) {
+        auto wait_time = std::chrono::milliseconds(100);
+        timed_out = m_cond.wait_for(lock, wait_time) == std::cv_status::timeout;
+      } else {
+        auto wait_time =
+            std::chrono::system_clock::now() + std::chrono::milliseconds(100);
+        timed_out =
+            m_cond.wait_until(lock, wait_time) == std::cv_status::timeout;
+      }
+      EXPECT_TRUE(lock.owns_lock())
+          << "The condition variable should have reacquired the lock.";
+      done = true;
+    };
+
+    // First, test without timing out.
+    timed_out = true;
+    StartThreads(wait_until);
+
+    NotifyAllTest();
+    EXPECT_FALSE(timed_out) << "The watcher should not have timed out.";
+
+    TearDown();
+
+    // Next, test and time out.
+    timed_out = false;
+    StartThreads(wait_until);
+
+    ShortSleep(110);
+
+    EXPECT_TRUE(m_done1) << "watcher1 should have timed out.";
+    EXPECT_TRUE(m_done2) << "watcher2 should have timed out.";
+    EXPECT_TRUE(timed_out) << "The watcher should have timed out.";
+  }
+
+  // For use with tests that have a timeout and a predicate.
+  void WaitTimePredicateTest(bool wait_for) {
+    // The condition_variable return value from the wait_for or wait_until
+    // function should in the case of having a predicate, by a boolean. If the
+    // predicate is true, then the return value will always be true. If the
+    // condition times out and, at the time of the timeout, the predicate is
+    // false, the return value will be false.
+    std::atomic<bool> retval{true};
+    auto predicate = [this]() -> bool { return m_pred_var; };
+    auto wait_until = [this, &retval, predicate,
+                       wait_for](std::atomic<bool>& done) {
+      priority_lock lock(m_mutex);
+      done = false;
+      if (wait_for) {
+        auto wait_time = std::chrono::milliseconds(100);
+        retval = m_cond.wait_for(lock, wait_time, predicate);
+      } else {
+        auto wait_time =
+            std::chrono::system_clock::now() + std::chrono::milliseconds(100);
+        retval = m_cond.wait_until(lock, wait_time, predicate);
+      }
+      EXPECT_TRUE(lock.owns_lock())
+          << "The condition variable should have reacquired the lock.";
+      done = true;
+    };
+
+    // Test without timing out and with the predicate set to true.
+    retval = true;
+    m_pred_var = true;
+    StartThreads(wait_until);
+
+    NotifyAllTest();
+    EXPECT_TRUE(retval) << "The watcher should not have timed out.";
+
+    TearDown();
+
+    // Test with timing out and with the predicate set to true.
+    retval = false;
+    m_pred_var = false;
+    StartThreads(wait_until);
+
+    ShortSleep(110);
+
+    EXPECT_TRUE(m_done1) << "watcher1 should have finished.";
+    EXPECT_TRUE(m_done2) << "watcher2 should have finished.";
+    EXPECT_FALSE(retval) << "The watcher should have timed out.";
+
+    TearDown();
+
+    // Test without timing out and run the PredicateTest().
+    retval = false;
+    StartThreads(wait_until);
+
+    PredicateTest();
+    EXPECT_TRUE(retval) << "The return value should have been true.";
+
+    TearDown();
+
+    // Test with timing out and the predicate set to true while we are waiting
+    // for the condition variable to time out.
+    retval = true;
+    StartThreads(wait_until);
+    ShortSleep();
+    m_pred_var = true;
+    ShortSleep(110);
+    EXPECT_TRUE(retval) << "The return value should have been true.";
+  }
+
+  virtual void TearDown() {
+    // If a thread has not completed, then continuing will cause the tests to
+    // hang forever and could cause issues. If we don't call detach, then
+    // std::terminate is called and all threads are terminated.
+    // Detaching is non-optimal, but should allow the rest of the tests to run
+    // before anything drastic occurs.
+    if (m_done1)
+      m_watcher1.join();
+    else
+      m_watcher1.detach();
+    if (m_done2)
+      m_watcher2.join();
+    else
+      m_watcher2.detach();
+  }
+};
+
+TEST_F(ConditionVariableTest, NotifyAll) {
+  auto wait = [this](std::atomic<bool>& done) {
+    priority_lock lock(m_mutex);
+    done = false;
+    m_cond.wait(lock);
+    EXPECT_TRUE(lock.owns_lock())
+        << "The condition variable should have reacquired the lock.";
+    done = true;
+  };
+
+  StartThreads(wait);
+
+  NotifyAllTest();
+}
+
+TEST_F(ConditionVariableTest, NotifyOne) {
+  auto wait = [this](std::atomic<bool>& done) {
+    priority_lock lock(m_mutex);
+    done = false;
+    m_cond.wait(lock);
+    EXPECT_TRUE(lock.owns_lock())
+        << "The condition variable should have reacquired the lock.";
+    done = true;
+  };
+
+  StartThreads(wait);
+
+  NotifyOne();
+  // Wait briefly to let things settle.
+  ShortSleep();
+  EXPECT_TRUE(m_done1 ^ m_done2) << "Only one thread should've been notified.";
+  NotifyOne();
+  ShortSleep();
+  EXPECT_TRUE(m_done2 && m_done2) << "Both threads should've been notified.";
+}
+
+TEST_F(ConditionVariableTest, WaitWithPredicate) {
+  auto predicate = [this]() -> bool { return m_pred_var; };
+  auto wait_predicate = [this, predicate](std::atomic<bool>& done) {
+    priority_lock lock(m_mutex);
+    done = false;
+    m_cond.wait(lock, predicate);
+    EXPECT_TRUE(lock.owns_lock())
+        << "The condition variable should have reacquired the lock.";
+    done = true;
+  };
+
+  StartThreads(wait_predicate);
+
+  PredicateTest();
+}
+
+TEST_F(ConditionVariableTest, WaitUntil) { WaitTimeTest(false); }
+
+TEST_F(ConditionVariableTest, WaitUntilWithPredicate) {
+  WaitTimePredicateTest(false);
+}
+
+TEST_F(ConditionVariableTest, WaitFor) { WaitTimeTest(true); }
+
+TEST_F(ConditionVariableTest, WaitForWithPredicate) {
+  WaitTimePredicateTest(true);
+}
+
+TEST_F(ConditionVariableTest, NativeHandle) {
+  auto wait = [this](std::atomic<bool>& done) {
+    priority_lock lock(m_mutex);
+    done = false;
+    m_cond.wait(lock);
+    EXPECT_TRUE(lock.owns_lock())
+        << "The condition variable should have reacquired the lock.";
+    done = true;
+  };
+
+  StartThreads(wait);
+
+  pthread_cond_t* native_handle = m_cond.native_handle();
+  pthread_cond_broadcast(native_handle);
+  ShortSleep();
+  EXPECT_TRUE(m_done1) << "watcher1 failed to be notified.";
+  EXPECT_TRUE(m_done2) << "watcher2 failed to be notified.";
+}
+
+}  // namespace testing
+}  // namespace wpilib