TimedConditionVariable.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. /**
  15. * @file TimedConditionVariable.hpp
  16. */
  17. #ifndef _UTILS_TIMEDCONDITIONVARIABLE_HPP_
  18. #define _UTILS_TIMEDCONDITIONVARIABLE_HPP_
  19. /*
  20. NOTE: Windows implementation temporary disabled due to aleatory high CPU consumption when
  21. calling _Cnd_timedwait function, making some tests to fail and very poor performance.
  22. Related task: #6274
  23. #if HAVE_STRICT_REALTIME && defined(_WIN32)
  24. #include <thr/xthreads.h>
  25. #define CLOCK_REALTIME 0
  26. #define CV_INIT_(x) _Cnd_init(x)
  27. #define CV_WAIT_(cv, x) _Cnd_wait(cv, (_Mtx_t)x)
  28. #define CV_TIMEDWAIT_(cv, x, y) _Cnd_timedwait(cv, (_Mtx_t)x, (xtime*)y)
  29. #define CV_SIGNAL_(cv) _Cnd_signal(cv)
  30. #define CV_BROADCAST_(cv) _Cnd_broadcast(cv)
  31. #define CV_T_ _Cnd_t
  32. extern int clock_gettime(int, struct timespec* tv);
  33. #elif HAVE_STRICT_REALTIME && defined(__linux__)
  34. */
  35. #if HAVE_STRICT_REALTIME && defined(__linux__)
  36. #include <pthread.h>
  37. #define CV_INIT_(x) pthread_cond_init(x, NULL);
  38. #define CV_WAIT_(cv, x) pthread_cond_wait(&cv, x)
  39. #define CV_TIMEDWAIT_(cv, x, y) pthread_cond_timedwait(&cv, x, y)
  40. #define CV_SIGNAL_(cv) pthread_cond_signal(&cv)
  41. #define CV_BROADCAST_(cv) pthread_cond_broadcast(&cv)
  42. #define CV_T_ pthread_cond_t
  43. #else
  44. #include <condition_variable>
  45. #endif
  46. #include <mutex>
  47. #include <chrono>
  48. #include <functional>
  49. namespace eprosima {
  50. namespace fastrtps {
  51. #if HAVE_STRICT_REALTIME && (/*defined(_WIN32) ||*/ defined(__linux__))
  52. class TimedConditionVariable
  53. {
  54. public:
  55. TimedConditionVariable()
  56. {
  57. CV_INIT_(&cv_);
  58. }
  59. template<typename Mutex>
  60. void wait(
  61. std::unique_lock<Mutex>& lock,
  62. std::function<bool()> predicate)
  63. {
  64. while (!predicate())
  65. {
  66. CV_WAIT_(cv_, lock.mutex()->native_handle());
  67. }
  68. }
  69. template<typename Mutex>
  70. void wait(
  71. std::unique_lock<Mutex>& lock)
  72. {
  73. CV_WAIT_(cv_, lock.mutex()->native_handle());
  74. }
  75. template<typename Mutex>
  76. bool wait_for(
  77. std::unique_lock<Mutex>& lock,
  78. const std::chrono::nanoseconds& max_blocking_time,
  79. std::function<bool()> predicate)
  80. {
  81. bool ret_value = true;
  82. auto nsecs = max_blocking_time;
  83. struct timespec max_wait = { 0, 0 };
  84. clock_gettime(CLOCK_REALTIME, &max_wait);
  85. nsecs = nsecs + std::chrono::nanoseconds(max_wait.tv_nsec);
  86. auto secs = std::chrono::duration_cast<std::chrono::seconds>(nsecs);
  87. nsecs -= secs;
  88. max_wait.tv_sec += secs.count();
  89. max_wait.tv_nsec = (long)nsecs.count();
  90. while (ret_value && false == (ret_value = predicate()))
  91. {
  92. ret_value = (0 == CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(), &max_wait));
  93. }
  94. return ret_value;
  95. }
  96. template<typename Mutex>
  97. bool wait_until(
  98. std::unique_lock<Mutex>& lock,
  99. const std::chrono::steady_clock::time_point& max_blocking_time,
  100. std::function<bool()> predicate)
  101. {
  102. auto secs = std::chrono::time_point_cast<std::chrono::seconds>(max_blocking_time);
  103. auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(max_blocking_time) -
  104. std::chrono::time_point_cast<std::chrono::nanoseconds>(secs);
  105. struct timespec max_wait = { secs.time_since_epoch().count(), ns.count() };
  106. bool ret_value = true;
  107. while (ret_value && false == (ret_value = predicate()))
  108. {
  109. ret_value = (CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(), &max_wait) == 0);
  110. }
  111. return ret_value;
  112. }
  113. template<typename Mutex>
  114. bool wait_until(
  115. std::unique_lock<Mutex>& lock,
  116. const std::chrono::steady_clock::time_point& max_blocking_time)
  117. {
  118. auto secs = std::chrono::time_point_cast<std::chrono::seconds>(max_blocking_time);
  119. auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(max_blocking_time) -
  120. std::chrono::time_point_cast<std::chrono::nanoseconds>(secs);
  121. struct timespec max_wait = { secs.time_since_epoch().count(), ns.count() };
  122. return (CV_TIMEDWAIT_(cv_, lock.mutex()->native_handle(), &max_wait) == 0);
  123. }
  124. void notify_one()
  125. {
  126. CV_SIGNAL_(cv_);
  127. }
  128. void notify_all()
  129. {
  130. CV_BROADCAST_(cv_);
  131. }
  132. private:
  133. CV_T_ cv_;
  134. };
  135. #else
  136. using TimedConditionVariable = std::condition_variable_any;
  137. #endif // HAVE_STRICT_REALTIME && (/*defined(_WIN32)*/ || defined(__linux__))
  138. } // namespace fastrtps
  139. } // namespace eprosima
  140. #endif // _UTILS_TIMEDCONDITIONVARIABLE_HPP_