condition.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP
  11. #define BOOST_INTERPROCESS_POSIX_CONDITION_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #
  16. #if defined(BOOST_HAS_PRAGMA_ONCE)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/config_begin.hpp>
  20. #include <boost/interprocess/detail/workaround.hpp>
  21. #include <boost/interprocess/sync/cv_status.hpp>
  22. #include <pthread.h>
  23. #include <errno.h>
  24. #include <boost/interprocess/sync/posix/pthread_helpers.hpp>
  25. #include <boost/interprocess/sync/posix/timepoint_to_timespec.hpp>
  26. #include <boost/interprocess/timed_utils.hpp>
  27. #include <boost/interprocess/sync/posix/mutex.hpp>
  28. #include <boost/assert.hpp>
  29. namespace boost {
  30. namespace interprocess {
  31. namespace ipcdetail {
  32. class posix_condition
  33. {
  34. //Non-copyable
  35. posix_condition(const posix_condition &);
  36. posix_condition &operator=(const posix_condition &);
  37. public:
  38. //!Constructs a posix_condition. On error throws interprocess_exception.
  39. posix_condition();
  40. //!Destroys *this
  41. //!liberating system resources.
  42. ~posix_condition();
  43. //!If there is a thread waiting on *this, change that
  44. //!thread's state to ready. Otherwise there is no effect.
  45. void notify_one();
  46. //!Change the state of all threads waiting on *this to ready.
  47. //!If there are no waiting threads, notify_all() has no effect.
  48. void notify_all();
  49. //!Releases the lock on the posix_mutex object associated with lock, blocks
  50. //!the current thread of execution until readied by a call to
  51. //!this->notify_one() or this->notify_all(), and then reacquires the lock.
  52. template <typename L>
  53. void wait(L& lock)
  54. {
  55. if (!lock)
  56. throw lock_exception();
  57. this->do_wait(*lock.mutex());
  58. }
  59. //!The same as:
  60. //!while (!pred()) wait(lock)
  61. template <typename L, typename Pr>
  62. void wait(L& lock, Pr pred)
  63. {
  64. if (!lock)
  65. throw lock_exception();
  66. while (!pred())
  67. this->do_wait(*lock.mutex());
  68. }
  69. //!Releases the lock on the posix_mutex object associated with lock, blocks
  70. //!the current thread of execution until readied by a call to
  71. //!this->notify_one() or this->notify_all(), or until time abs_time is reached,
  72. //!and then reacquires the lock.
  73. //!Returns: false if time abs_time is reached, otherwise true.
  74. template <typename L, typename TimePoint>
  75. bool timed_wait(L& lock, const TimePoint &abs_time)
  76. {
  77. if (!lock)
  78. throw lock_exception();
  79. //Posix does not support infinity absolute time so handle it here
  80. if(ipcdetail::is_pos_infinity(abs_time)){
  81. this->wait(lock);
  82. return true;
  83. }
  84. return this->do_timed_wait(abs_time, *lock.mutex());
  85. }
  86. //!The same as: while (!pred()) {
  87. //! if (!timed_wait(lock, abs_time)) return pred();
  88. //! } return true;
  89. template <typename L, typename TimePoint, typename Pr>
  90. bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred)
  91. {
  92. if (!lock)
  93. throw lock_exception();
  94. //Posix does not support infinity absolute time so handle it here
  95. if(ipcdetail::is_pos_infinity(abs_time)){
  96. this->wait(lock, pred);
  97. return true;
  98. }
  99. while (!pred()){
  100. if (!this->do_timed_wait(abs_time, *lock.mutex()))
  101. return pred();
  102. }
  103. return true;
  104. }
  105. //!Same as `timed_wait`, but this function is modeled after the
  106. //!standard library interface.
  107. template <typename L, class TimePoint>
  108. cv_status wait_until(L& lock, const TimePoint &abs_time)
  109. { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; }
  110. //!Same as `timed_wait`, but this function is modeled after the
  111. //!standard library interface.
  112. template <typename L, class TimePoint, typename Pr>
  113. bool wait_until(L& lock, const TimePoint &abs_time, Pr pred)
  114. { return this->timed_wait(lock, abs_time, pred); }
  115. template <typename L, class Duration>
  116. cv_status wait_for(L& lock, const Duration &dur)
  117. { return this->wait_until(lock, duration_to_ustime(dur)) ? cv_status::no_timeout : cv_status::timeout; }
  118. template <typename L, class Duration, typename Pr>
  119. bool wait_for(L& lock, const Duration &dur, Pr pred)
  120. { return this->wait_until(lock, duration_to_ustime(dur), pred); }
  121. void do_wait(posix_mutex &mut);
  122. template<class TimePoint>
  123. bool do_timed_wait(const TimePoint &abs_time, posix_mutex &mut);
  124. private:
  125. pthread_cond_t m_condition;
  126. };
  127. inline posix_condition::posix_condition()
  128. {
  129. int res;
  130. pthread_condattr_t cond_attr;
  131. res = pthread_condattr_init(&cond_attr);
  132. if(res != 0){
  133. throw interprocess_exception("pthread_condattr_init failed");
  134. }
  135. res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
  136. if(res != 0){
  137. pthread_condattr_destroy(&cond_attr);
  138. throw interprocess_exception(res);
  139. }
  140. res = pthread_cond_init(&m_condition, &cond_attr);
  141. pthread_condattr_destroy(&cond_attr);
  142. if(res != 0){
  143. throw interprocess_exception(res);
  144. }
  145. }
  146. inline posix_condition::~posix_condition()
  147. {
  148. int res = 0;
  149. res = pthread_cond_destroy(&m_condition);
  150. BOOST_ASSERT(res == 0); (void)res;
  151. }
  152. inline void posix_condition::notify_one()
  153. {
  154. int res = 0;
  155. res = pthread_cond_signal(&m_condition);
  156. BOOST_ASSERT(res == 0); (void)res;
  157. }
  158. inline void posix_condition::notify_all()
  159. {
  160. int res = 0;
  161. res = pthread_cond_broadcast(&m_condition);
  162. BOOST_ASSERT(res == 0); (void)res;
  163. }
  164. inline void posix_condition::do_wait(posix_mutex &mut)
  165. {
  166. pthread_mutex_t* pmutex = &mut.m_mut;
  167. int res = 0;
  168. res = pthread_cond_wait(&m_condition, pmutex);
  169. BOOST_ASSERT(res == 0); (void)res;
  170. }
  171. template<class TimePoint>
  172. inline bool posix_condition::do_timed_wait
  173. (const TimePoint &abs_time, posix_mutex &mut)
  174. {
  175. timespec ts = timepoint_to_timespec(abs_time);
  176. pthread_mutex_t* pmutex = &mut.m_mut;
  177. int res = 0;
  178. res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
  179. BOOST_ASSERT(res == 0 || res == ETIMEDOUT);
  180. return res != ETIMEDOUT;
  181. }
  182. } //namespace ipcdetail
  183. } //namespace interprocess
  184. } //namespace boost
  185. #include <boost/interprocess/detail/config_end.hpp>
  186. #endif //#ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP