Squashed 'third_party/allwpilib_2016/' content from commit 7f61816
Change-Id: If9d9245880859cdf580f5d7f77045135d0521ce7
git-subtree-dir: third_party/allwpilib_2016
git-subtree-split: 7f618166ed253a24629934fcf89c3decb0528a3b
diff --git a/hal/include/HAL/cpp/Resource.hpp b/hal/include/HAL/cpp/Resource.hpp
new file mode 100644
index 0000000..ae31996
--- /dev/null
+++ b/hal/include/HAL/cpp/Resource.hpp
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2008. 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 $(WIND_BASE)/WPILib. */
+/*----------------------------------------------------------------------------*/
+#pragma once
+
+#include "../Errors.hpp"
+#include "HAL/cpp/priority_mutex.h"
+#include <stdint.h>
+
+#include <vector>
+
+// TODO: Replace this with something appropriate to avoid conflicts with
+// wpilibC++ Resource class (which performs an essentially identical function).
+namespace hal {
+
+/**
+ * The Resource class is a convenient way to track allocated resources.
+ * It tracks them as indicies in the range [0 .. elements - 1].
+ * E.g. the library uses this to track hardware channel allocation.
+ *
+ * The Resource class does not allocate the hardware channels or other
+ * resources; it just tracks which indices were marked in use by
+ * Allocate and not yet freed by Free.
+ */
+class Resource
+{
+public:
+ Resource(const Resource&) = delete;
+ Resource& operator=(const Resource&) = delete;
+ explicit Resource(uint32_t size);
+ virtual ~Resource() = default;
+ static void CreateResourceObject(Resource **r, uint32_t elements);
+ uint32_t Allocate(const char *resourceDesc);
+ uint32_t Allocate(uint32_t index, const char *resourceDesc);
+ void Free(uint32_t index);
+
+private:
+ std::vector<bool> m_isAllocated;
+ priority_recursive_mutex m_allocateLock;
+
+ static priority_recursive_mutex m_createLock;
+};
+
+} // namespace hal
diff --git a/hal/include/HAL/cpp/Semaphore.hpp b/hal/include/HAL/cpp/Semaphore.hpp
new file mode 100644
index 0000000..6a6374b
--- /dev/null
+++ b/hal/include/HAL/cpp/Semaphore.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <cstdint>
+#include <condition_variable>
+
+#include "HAL/cpp/priority_mutex.h"
+
+class Semaphore {
+ public:
+ explicit Semaphore(uint32_t count = 0);
+ Semaphore(Semaphore&&);
+ Semaphore& operator=(Semaphore&&);
+
+ void give();
+ void take();
+
+ // @return true if semaphore was locked successfully. false if not.
+ bool tryTake();
+
+ static const int32_t kNoWait = 0;
+ static const int32_t kWaitForever = -1;
+
+ static const uint32_t kEmpty = 0;
+ static const uint32_t kFull = 1;
+
+ private:
+ priority_mutex m_mutex;
+ std::condition_variable_any m_condition;
+ uint32_t m_count = 0;
+};
diff --git a/hal/include/HAL/cpp/priority_condition_variable.h b/hal/include/HAL/cpp/priority_condition_variable.h
new file mode 100644
index 0000000..e8ab9e5
--- /dev/null
+++ b/hal/include/HAL/cpp/priority_condition_variable.h
@@ -0,0 +1,117 @@
+#pragma once
+
+/* std::condition_variable provides the native_handle() method to return its
+ * underlying pthread_cond_t*. WPILib uses this to interface with the FRC
+ * network communication library. Since WPILib uses a custom mutex class and
+ * not std::mutex, std::condition_variable_any must be used instead.
+ * std::condition_variable_any doesn't expose its internal handle, so this
+ * class provides the same interface and implementation in addition to a
+ * native_handle() method.
+ */
+
+#include <condition_variable>
+#include <memory>
+#include "priority_mutex.h"
+
+class priority_condition_variable {
+ typedef std::chrono::system_clock clock_t;
+
+ public:
+ typedef std::condition_variable::native_handle_type native_handle_type;
+
+ priority_condition_variable() : m_mutex(std::make_shared<std::mutex>()) {}
+ ~priority_condition_variable() = default;
+
+ priority_condition_variable(const priority_condition_variable&) = delete;
+ priority_condition_variable& operator=(const priority_condition_variable&) = delete;
+
+ void notify_one() noexcept {
+ std::lock_guard<std::mutex> lock(*m_mutex);
+ m_cond.notify_one();
+ }
+
+ void notify_all() noexcept {
+ std::lock_guard<std::mutex> lock(*m_mutex);
+ m_cond.notify_all();
+ }
+
+ template<typename Lock>
+ void wait(Lock& _lock) {
+ std::shared_ptr<std::mutex> _mutex = m_mutex;
+ std::unique_lock<std::mutex> my_lock(*_mutex);
+ Unlock<Lock> unlock(_lock);
+
+ // *mutex must be unlocked before re-locking _lock so move
+ // ownership of *_mutex lock to an object with shorter lifetime.
+ std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
+ m_cond.wait(my_lock2);
+ }
+
+ template<typename Lock, typename Predicate>
+ void wait(Lock& lock, Predicate p) {
+ while (!p()) { wait(lock); }
+ }
+
+ template<typename Lock, typename Clock, typename Duration>
+ std::cv_status wait_until(Lock& _lock,
+ const std::chrono::time_point<Clock, Duration>& atime) {
+ std::shared_ptr<std::mutex> _mutex = m_mutex;
+ std::unique_lock<std::mutex> my_lock(*_mutex);
+ Unlock<Lock> unlock(_lock);
+
+ // *_mutex must be unlocked before re-locking _lock so move
+ // ownership of *_mutex lock to an object with shorter lifetime.
+ std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
+ return m_cond.wait_until(my_lock2, atime);
+ }
+
+ template<typename Lock, typename Clock, typename Duration, typename Predicate>
+ bool wait_until(Lock& lock,
+ const std::chrono::time_point<Clock, Duration>& atime, Predicate p) {
+ while (!p()) {
+ if (wait_until(lock, atime) == std::cv_status::timeout) {
+ return p();
+ }
+ }
+ return true;
+ }
+
+ template<typename Lock, typename Rep, typename Period>
+ std::cv_status wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime) {
+ return wait_until(lock, clock_t::now() + rtime);
+ }
+
+ template<typename Lock, typename Rep, typename Period, typename Predicate>
+ bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime,
+ Predicate p) {
+ return wait_until(lock, clock_t::now() + rtime, std::move(p));
+ }
+
+ native_handle_type native_handle() {
+ return m_cond.native_handle();
+ }
+
+ private:
+ std::condition_variable m_cond;
+ std::shared_ptr<std::mutex> m_mutex;
+
+ // scoped unlock - unlocks in ctor, re-locks in dtor
+ template<typename Lock>
+ struct Unlock {
+ explicit Unlock(Lock& lk) : m_lock(lk) { lk.unlock(); }
+
+ ~Unlock() /*noexcept(false)*/ {
+ if (std::uncaught_exception()) {
+ try { m_lock.lock(); } catch(...) {}
+ }
+ else {
+ m_lock.lock();
+ }
+ }
+
+ Unlock(const Unlock&) = delete;
+ Unlock& operator=(const Unlock&) = delete;
+
+ Lock& m_lock;
+ };
+};
diff --git a/hal/include/HAL/cpp/priority_mutex.h b/hal/include/HAL/cpp/priority_mutex.h
new file mode 100644
index 0000000..16e88f6
--- /dev/null
+++ b/hal/include/HAL/cpp/priority_mutex.h
@@ -0,0 +1,76 @@
+#pragma once
+
+// Allows usage with std::lock_guard without including <mutex> separately
+#include <mutex>
+
+#ifdef FRC_SIMULATOR
+// We do not want to use pthreads if in the simulator; however, in the
+// simulator, we do not care about priority inversion.
+typedef std::mutex priority_mutex;
+typedef std::recursive_mutex priority_recursive_mutex;
+#else // Covers rest of file.
+
+#include <pthread.h>
+
+class priority_recursive_mutex {
+ public:
+ typedef pthread_mutex_t *native_handle_type;
+
+ constexpr priority_recursive_mutex() noexcept = default;
+ priority_recursive_mutex(const priority_recursive_mutex &) = delete;
+ priority_recursive_mutex &operator=(const priority_recursive_mutex &) = delete;
+
+ // Lock the mutex, blocking until it's available.
+ void lock();
+
+ // Unlock the mutex.
+ void unlock();
+
+ // Tries to lock the mutex.
+ bool try_lock() noexcept;
+
+ pthread_mutex_t *native_handle();
+
+ private:
+ // Do the equivalent of setting PTHREAD_PRIO_INHERIT and
+ // PTHREAD_MUTEX_RECURSIVE_NP.
+#if __WORDSIZE == 64
+ pthread_mutex_t m_mutex = {
+ {0, 0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, 0, 0, {0, 0}}};
+#else
+ pthread_mutex_t m_mutex = {
+ {0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, 0, {0}}};
+#endif
+};
+
+class priority_mutex {
+ public:
+ typedef pthread_mutex_t *native_handle_type;
+
+ constexpr priority_mutex() noexcept = default;
+ priority_mutex(const priority_mutex &) = delete;
+ priority_mutex &operator=(const priority_mutex &) = delete;
+
+ // Lock the mutex, blocking until it's available.
+ void lock();
+
+ // Unlock the mutex.
+ void unlock();
+
+ // Tries to lock the mutex.
+ bool try_lock() noexcept;
+
+ pthread_mutex_t *native_handle();
+
+ private:
+ // Do the equivalent of setting PTHREAD_PRIO_INHERIT.
+#if __WORDSIZE == 64
+ pthread_mutex_t m_mutex = {
+ {0, 0, 0, 0, 0x20, 0, 0, {0, 0}}};
+#else
+ pthread_mutex_t m_mutex = {
+ {0, 0, 0, 0x20, 0, {0}}};
+#endif
+};
+
+#endif // FRC_SIMULATOR