WPILibC++  unspecified
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Pages
priority_condition_variable.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2016. 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 "priority_mutex.h"
22 
24  typedef std::chrono::system_clock clock_t;
25 
26  public:
27  typedef std::condition_variable::native_handle_type native_handle_type;
28 
29  priority_condition_variable() : m_mutex(std::make_shared<std::mutex>()) {}
30  ~priority_condition_variable() = default;
31 
33  priority_condition_variable& operator=(const priority_condition_variable&) = delete;
34 
35  void notify_one() noexcept {
36  std::lock_guard<std::mutex> lock(*m_mutex);
37  m_cond.notify_one();
38  }
39 
40  void notify_all() noexcept {
41  std::lock_guard<std::mutex> lock(*m_mutex);
42  m_cond.notify_all();
43  }
44 
45  template<typename Lock>
46  void wait(Lock& _lock) {
47  std::shared_ptr<std::mutex> _mutex = m_mutex;
48  std::unique_lock<std::mutex> my_lock(*_mutex);
49  Unlock<Lock> unlock(_lock);
50 
51  // *mutex must be unlocked before re-locking _lock so move
52  // ownership of *_mutex lock to an object with shorter lifetime.
53  std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
54  m_cond.wait(my_lock2);
55  }
56 
57  template<typename Lock, typename Predicate>
58  void wait(Lock& lock, Predicate p) {
59  while (!p()) { wait(lock); }
60  }
61 
62  template<typename Lock, typename Clock, typename Duration>
63  std::cv_status wait_until(Lock& _lock,
64  const std::chrono::time_point<Clock, Duration>& atime) {
65  std::shared_ptr<std::mutex> _mutex = m_mutex;
66  std::unique_lock<std::mutex> my_lock(*_mutex);
67  Unlock<Lock> unlock(_lock);
68 
69  // *_mutex must be unlocked before re-locking _lock so move
70  // ownership of *_mutex lock to an object with shorter lifetime.
71  std::unique_lock<std::mutex> my_lock2(std::move(my_lock));
72  return m_cond.wait_until(my_lock2, atime);
73  }
74 
75  template<typename Lock, typename Clock, typename Duration, typename Predicate>
76  bool wait_until(Lock& lock,
77  const std::chrono::time_point<Clock, Duration>& atime, Predicate p) {
78  while (!p()) {
79  if (wait_until(lock, atime) == std::cv_status::timeout) {
80  return p();
81  }
82  }
83  return true;
84  }
85 
86  template<typename Lock, typename Rep, typename Period>
87  std::cv_status wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime) {
88  return wait_until(lock, clock_t::now() + rtime);
89  }
90 
91  template<typename Lock, typename Rep, typename Period, typename Predicate>
92  bool wait_for(Lock& lock, const std::chrono::duration<Rep, Period>& rtime,
93  Predicate p) {
94  return wait_until(lock, clock_t::now() + rtime, std::move(p));
95  }
96 
97  native_handle_type native_handle() {
98  return m_cond.native_handle();
99  }
100 
101  private:
102  std::condition_variable m_cond;
103  std::shared_ptr<std::mutex> m_mutex;
104 
105  // scoped unlock - unlocks in ctor, re-locks in dtor
106  template<typename Lock>
107  struct Unlock {
108  explicit Unlock(Lock& lk) : m_lock(lk) { lk.unlock(); }
109 
110  ~Unlock() /*noexcept(false)*/ {
111  if (std::uncaught_exception()) {
112  try { m_lock.lock(); } catch(...) {}
113  }
114  else {
115  m_lock.lock();
116  }
117  }
118 
119  Unlock(const Unlock&) = delete;
120  Unlock& operator=(const Unlock&) = delete;
121 
122  Lock& m_lock;
123  };
124 };
Definition: priority_condition_variable.h:23