Fast DDS  Version 3.6.1.0
Fast DDS
TimedConditionVariable.hpp
1 // Copyright 2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
19 #ifndef FASTDDS_UTILS__TIMEDCONDITIONVARIABLE_HPP
20 #define FASTDDS_UTILS__TIMEDCONDITIONVARIABLE_HPP
21 
22 #include <fastdds/config.hpp>
23 
24 /*
25  NOTE: Windows implementation temporary disabled due to aleatory high CPU consumption when
26  calling _Cnd_timedwait function, making some tests to fail and very poor performance.
27  Related task: #6274
28 
29  #if HAVE_STRICT_REALTIME && defined(_WIN32)
30  #include <thr/xthreads.h>
31 
32  #define CLOCK_REALTIME 0
33  #define CV_INIT_(x) _Cnd_init(x)
34  #define CV_WAIT_(cv, x) _Cnd_wait(cv, (_Mtx_t)x)
35  #define CV_TIMEDWAIT_(cv, x, y) _Cnd_timedwait(cv, (_Mtx_t)x, (xtime*)y)
36  #define CV_SIGNAL_(cv) _Cnd_signal(cv)
37  #define CV_BROADCAST_(cv) _Cnd_broadcast(cv)
38  #define CV_T_ _Cnd_t
39 
40  extern int clock_gettime(int, struct timespec* tv);
41  #elif HAVE_STRICT_REALTIME && defined(__unix__)
42  */
43 #if HAVE_STRICT_REALTIME && defined(__unix__)
44 #include <pthread.h>
45 
46 #define CV_INIT_(x) pthread_condattr_init(&cv_attr_); \
47  pthread_condattr_setclock(&cv_attr_, CLOCK_MONOTONIC); \
48  pthread_cond_init(x, &cv_attr_);
49 #define CV_WAIT_(cv, x) pthread_cond_wait(&cv, x)
50 #define CV_TIMEDWAIT_(cv, x, y) pthread_cond_timedwait(&cv, x, y)
51 #define CV_SIGNAL_(cv) pthread_cond_signal(&cv)
52 #define CV_BROADCAST_(cv) pthread_cond_broadcast(&cv)
53 #define CV_T_ pthread_condattr_t cv_attr_; pthread_cond_t
54 #else
55 #include <condition_variable>
56 #endif // if HAVE_STRICT_REALTIME && defined(__unix__)
57 
58 #include <mutex>
59 #include <condition_variable>
60 #include <chrono>
61 #include <functional>
62 
63 namespace eprosima {
64 namespace fastdds {
65 
66 #if HAVE_STRICT_REALTIME && (/*defined(_WIN32) ||*/ defined(__unix__))
67 
68 class TimedConditionVariable
69 {
70 public:
71 
72  TimedConditionVariable()
73  {
74  CV_INIT_(&cv_);
75  }
76 
77  template<typename Mutex>
78  void wait(
79  std::unique_lock<Mutex>& lock,
80  std::function<bool()> predicate)
81  {
82  while (!predicate())
83  {
84  CV_WAIT_(cv_, lock.mutex()->native_handle());
85  }
86  }
87 
88  template<typename Mutex>
89  void wait(
90  std::unique_lock<Mutex>& lock)
91  {
92  CV_WAIT_(cv_, lock.mutex()->native_handle());
93  }
94 
95  template<typename Mutex>
96  bool wait_for(
97  std::unique_lock<Mutex>& lock,
98  const std::chrono::nanoseconds& max_blocking_time,
99  std::function<bool()> predicate)
100  {
101  bool ret_value = true;
102  auto nsecs = max_blocking_time;
103  struct timespec max_wait = {
104  0, 0
105  };
106  clock_gettime(CLOCK_MONOTONIC, &max_wait);
107  nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
108  auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
109  nsecs -= secs;
110  max_wait.tv_sec += secs.count();
111  max_wait.tv_nsec = (long)nsecs.count();
112  while (ret_value && false == (ret_value = predicate()))
113  {
114  ret_value = (0 == CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(), &max_wait));
115  }
116 
117  return ret_value;
118  }
119 
120  template<typename Mutex>
121  std::cv_status wait_for(
122  std::unique_lock<Mutex>& lock,
123  const std::chrono::nanoseconds& max_blocking_time)
124  {
125  auto nsecs = max_blocking_time;
126  struct timespec max_wait = {
127  0, 0
128  };
129  clock_gettime(CLOCK_MONOTONIC, &max_wait);
130  nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
131  auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
132  nsecs -= secs;
133  max_wait.tv_sec += secs.count();
134  max_wait.tv_nsec = (long)nsecs.count();
135  return (CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(),
136  &max_wait) == 0) ? std::cv_status::no_timeout : std::cv_status::timeout;
137  }
138 
139  template<typename Mutex>
140  bool wait_until(
141  std::unique_lock<Mutex>& lock,
142  const std::chrono::steady_clock::time_point& max_blocking_time,
143  std::function<bool()> predicate)
144  {
145  auto secs = std::chrono::time_point_cast<std::chrono::seconds>(max_blocking_time);
146  auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(max_blocking_time) -
147  std::chrono::time_point_cast<std::chrono::nanoseconds>(secs);
148  struct timespec max_wait = {
149  secs.time_since_epoch().count(), ns.count()
150  };
151  bool ret_value = true;
152  while (ret_value && false == (ret_value = predicate()))
153  {
154  ret_value = (CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(), &max_wait) == 0);
155  }
156 
157  return ret_value;
158  }
159 
160  template<typename Mutex>
161  std::cv_status wait_until(
162  std::unique_lock<Mutex>& lock,
163  const std::chrono::steady_clock::time_point& max_blocking_time)
164  {
165  auto secs = std::chrono::time_point_cast<std::chrono::seconds>(max_blocking_time);
166  auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(max_blocking_time) -
167  std::chrono::time_point_cast<std::chrono::nanoseconds>(secs);
168  struct timespec max_wait = {
169  secs.time_since_epoch().count(), ns.count()
170  };
171  return (CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(),
172  &max_wait) == 0) ? std::cv_status::no_timeout : std::cv_status::timeout;
173  }
174 
175  void notify_one()
176  {
177  CV_SIGNAL_(cv_);
178  }
179 
180  void notify_all()
181  {
182  CV_BROADCAST_(cv_);
183  }
184 
185 private:
186 
187  CV_T_ cv_;
188 };
189 #else
190 using TimedConditionVariable = std::condition_variable_any;
191 #endif // HAVE_STRICT_REALTIME && (/*defined(_WIN32)*/ || defined(__unix__))
192 
193 } // namespace fastdds
194 } // namespace eprosima
195 
196 #endif // FASTDDS_UTILS__TIMEDCONDITIONVARIABLE_HPP