WPILibC++  unspecified
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Pages
priority_condition_variable.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2016-2017. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #pragma once
9 
10 /* std::condition_variable provides the native_handle() method to return its
11  * underlying pthread_cond_t*. WPILib uses this to interface with the FRC
12  * network communication library. Since WPILib uses a custom mutex class and
13  * not std::mutex, std::condition_variable_any must be used instead.
14  * std::condition_variable_any doesn't expose its internal handle, so this
15  * class provides the same interface and implementation in addition to a
16  * native_handle() method.
17  */
18 
19 #include <condition_variable>
20 #include <memory>
21 #include <utility>
22 
23 #include "priority_mutex.h"
24 
25 namespace hal {
26 
28  typedef std::chrono::system_clock clock;
29 
30  public:
31  typedef std::condition_variable::native_handle_type native_handle_type;
32 
33  priority_condition_variable() : m_mutex(std::make_shared<std::mutex>()) {}
34  ~priority_condition_variable() = default;
35 
38  delete;
39 
40  void notify_one() noexcept {
41  std::lock_guard<std::mutex> lock(*m_mutex);
42  m_cond.notify_one();
43  }
44 
45  void notify_all() noexcept {
46  std::lock_guard<std::mutex> lock(*m_mutex);
47  m_cond.notify_all();
48  }
49 
50  template <typename Lock>
51  void wait(Lock& _lock) {
52  std::shared_ptr<std::mutex> _mutex = m_mutex;
53  std::unique_lock<std::mutex> my_lock(*_mutex);
54  Unlock<Lock> unlock(_lock);
55 
56  // *mutex must be unlocked before re-locking _lock so move
57  // ownership of *_mutex lock to an object with shorter lifetime.
58  std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
59  m_cond.wait(my_lock2);
60  }
61 
62  template <typename Lock, typename Predicate>
63  void wait(Lock& lock, Predicate p) {
64  while (!p()) {
65  wait(lock);
66  }
67  }
68 
69  template <typename Lock, typename Clock, typename Duration>
70  std::cv_status wait_until(
71  Lock& _lock, const std::chrono::time_point<Clock, Duration>& atime) {
72  std::shared_ptr<std::mutex> _mutex = m_mutex;
73  std::unique_lock<std::mutex> my_lock(*_mutex);
74  Unlock<Lock> unlock(_lock);
75 
76  // *_mutex must be unlocked before re-locking _lock so move
77  // ownership of *_mutex lock to an object with shorter lifetime.
78  std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
79  return m_cond.wait_until(my_lock2, atime);
80  }
81 
82  template <typename Lock, typename Clock, typename Duration,
83  typename Predicate>
84  bool wait_until(Lock& lock,
85  const std::chrono::time_point<Clock, Duration>& atime,
86  Predicate p) {
87  while (!p()) {
88  if (wait_until(lock, atime) == std::cv_status::timeout) {
89  return p();
90  }
91  }
92  return true;
93  }
94 
95  template <typename Lock, typename Rep, typename Period>
96  std::cv_status wait_for(Lock& lock,
97  const std::chrono::duration<Rep, Period>& rtime) {
98  return wait_until(lock, clock::now() + rtime);
99  }
100 
101  template <typename Lock, typename Rep, typename Period, typename Predicate>
102  bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime,
103  Predicate p) {
104  return wait_until(lock, clock::now() + rtime, std::move(p));
105  }
106 
107  native_handle_type native_handle() { return m_cond.native_handle(); }
108 
109  private:
110  std::condition_variable m_cond;
111  std::shared_ptr<std::mutex> m_mutex;
112 
113  // scoped unlock - unlocks in ctor, re-locks in dtor
114  template <typename Lock>
115  struct Unlock {
116  explicit Unlock(Lock& lk) : m_lock(lk) { lk.unlock(); }
117 
118  ~Unlock() /*noexcept(false)*/ {
119  if (std::uncaught_exception()) {
120  try {
121  m_lock.lock();
122  } catch (...) {
123  }
124  } else {
125  m_lock.lock();
126  }
127  }
128 
129  Unlock(const Unlock&) = delete;
130  Unlock& operator=(const Unlock&) = delete;
131 
132  Lock& m_lock;
133  };
134 };
135 
136 } // namespace hal
137 
138 // For backwards compatibility
139 #ifndef NAMESPACED_PRIORITY
140 using hal::priority_condition_variable; // NOLINT
141 #endif
Definition: priority_condition_variable.h:27