condition.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 <pthread.h>
  22. #include <errno.h>
  23. #include <boost/interprocess/sync/posix/pthread_helpers.hpp>
  24. #include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
  25. #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
  26. #include <boost/interprocess/sync/posix/mutex.hpp>
  27. #include <boost/assert.hpp>
  28. namespace boost {
  29. namespace interprocess {
  30. namespace ipcdetail {
  31. class posix_condition
  32. {
  33. //Non-copyable
  34. posix_condition(const posix_condition &);
  35. posix_condition &operator=(const posix_condition &);
  36. public:
  37. //!Constructs a posix_condition. On error throws interprocess_exception.
  38. posix_condition();
  39. //!Destroys *this
  40. //!liberating system resources.
  41. ~posix_condition();
  42. //!If there is a thread waiting on *this, change that
  43. //!thread's state to ready. Otherwise there is no effect.
  44. void notify_one();
  45. //!Change the state of all threads waiting on *this to ready.
  46. //!If there are no waiting threads, notify_all() has no effect.
  47. void notify_all();
  48. //!Releases the lock on the posix_mutex object associated with lock, blocks
  49. //!the current thread of execution until readied by a call to
  50. //!this->notify_one() or this->notify_all(), and then reacquires the lock.
  51. template <typename L>
  52. void wait(L& lock)
  53. {
  54. if (!lock)
  55. throw lock_exception();
  56. this->do_wait(*lock.mutex());
  57. }
  58. //!The same as:
  59. //!while (!pred()) wait(lock)
  60. template <typename L, typename Pr>
  61. void wait(L& lock, Pr pred)
  62. {
  63. if (!lock)
  64. throw lock_exception();
  65. while (!pred())
  66. this->do_wait(*lock.mutex());
  67. }
  68. //!Releases the lock on the posix_mutex object associated with lock, blocks
  69. //!the current thread of execution until readied by a call to
  70. //!this->notify_one() or this->notify_all(), or until time abs_time is reached,
  71. //!and then reacquires the lock.
  72. //!Returns: false if time abs_time is reached, otherwise true.
  73. template <typename L>
  74. bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
  75. {
  76. if (!lock)
  77. throw lock_exception();
  78. //Posix does not support infinity absolute time so handle it here
  79. if(abs_time == boost::posix_time::pos_infin){
  80. this->wait(lock);
  81. return true;
  82. }
  83. return this->do_timed_wait(abs_time, *lock.mutex());
  84. }
  85. //!The same as: while (!pred()) {
  86. //! if (!timed_wait(lock, abs_time)) return pred();
  87. //! } return true;
  88. template <typename L, typename Pr>
  89. bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
  90. {
  91. if (!lock)
  92. throw lock_exception();
  93. //Posix does not support infinity absolute time so handle it here
  94. if(abs_time == boost::posix_time::pos_infin){
  95. this->wait(lock, pred);
  96. return true;
  97. }
  98. while (!pred()){
  99. if (!this->do_timed_wait(abs_time, *lock.mutex()))
  100. return pred();
  101. }
  102. return true;
  103. }
  104. void do_wait(posix_mutex &mut);
  105. bool do_timed_wait(const boost::posix_time::ptime &abs_time, posix_mutex &mut);
  106. private:
  107. pthread_cond_t m_condition;
  108. };
  109. inline posix_condition::posix_condition()
  110. {
  111. int res;
  112. pthread_condattr_t cond_attr;
  113. res = pthread_condattr_init(&cond_attr);
  114. if(res != 0){
  115. throw interprocess_exception("pthread_condattr_init failed");
  116. }
  117. res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
  118. if(res != 0){
  119. pthread_condattr_destroy(&cond_attr);
  120. throw interprocess_exception(res);
  121. }
  122. res = pthread_cond_init(&m_condition, &cond_attr);
  123. pthread_condattr_destroy(&cond_attr);
  124. if(res != 0){
  125. throw interprocess_exception(res);
  126. }
  127. }
  128. inline posix_condition::~posix_condition()
  129. {
  130. int res = 0;
  131. res = pthread_cond_destroy(&m_condition);
  132. BOOST_ASSERT(res == 0); (void)res;
  133. }
  134. inline void posix_condition::notify_one()
  135. {
  136. int res = 0;
  137. res = pthread_cond_signal(&m_condition);
  138. BOOST_ASSERT(res == 0); (void)res;
  139. }
  140. inline void posix_condition::notify_all()
  141. {
  142. int res = 0;
  143. res = pthread_cond_broadcast(&m_condition);
  144. BOOST_ASSERT(res == 0); (void)res;
  145. }
  146. inline void posix_condition::do_wait(posix_mutex &mut)
  147. {
  148. pthread_mutex_t* pmutex = &mut.m_mut;
  149. int res = 0;
  150. res = pthread_cond_wait(&m_condition, pmutex);
  151. BOOST_ASSERT(res == 0); (void)res;
  152. }
  153. inline bool posix_condition::do_timed_wait
  154. (const boost::posix_time::ptime &abs_time, posix_mutex &mut)
  155. {
  156. timespec ts = ptime_to_timespec(abs_time);
  157. pthread_mutex_t* pmutex = &mut.m_mut;
  158. int res = 0;
  159. res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
  160. BOOST_ASSERT(res == 0 || res == ETIMEDOUT);
  161. return res != ETIMEDOUT;
  162. }
  163. } //namespace ipcdetail
  164. } //namespace interprocess
  165. } //namespace boost
  166. #include <boost/interprocess/detail/config_end.hpp>
  167. #endif //#ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP