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