]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/signals2/connection.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / signals2 / connection.hpp
1 /*
2 boost::signals2::connection provides a handle to a signal/slot connection.
3
4 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
5 Begin: 2007-01-23
6 */
7 // Copyright Frank Mori Hess 2007-2008.
8 // Distributed under the Boost Software License, Version
9 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11
12 // See http://www.boost.org/libs/signals2 for library home page.
13
14 #ifndef BOOST_SIGNALS2_CONNECTION_HPP
15 #define BOOST_SIGNALS2_CONNECTION_HPP
16
17 #include <boost/config.hpp>
18 #include <boost/function.hpp>
19 #include <boost/mpl/bool.hpp>
20 #include <boost/noncopyable.hpp>
21 #include <boost/shared_ptr.hpp>
22 #include <boost/signals2/detail/auto_buffer.hpp>
23 #include <boost/signals2/detail/null_output_iterator.hpp>
24 #include <boost/signals2/detail/unique_lock.hpp>
25 #include <boost/signals2/slot.hpp>
26 #include <boost/weak_ptr.hpp>
27
28 namespace boost
29 {
30 namespace signals2
31 {
32 inline void null_deleter(const void*) {}
33 namespace detail
34 {
35 // This lock maintains a list of shared_ptr<void>
36 // which will be destroyed only after the lock
37 // has released its mutex. Used to garbage
38 // collect disconnected slots
39 template<typename Mutex>
40 class garbage_collecting_lock: public noncopyable
41 {
42 public:
43 garbage_collecting_lock(Mutex &m):
44 lock(m)
45 {}
46 void add_trash(const shared_ptr<void> &piece_of_trash)
47 {
48 garbage.push_back(piece_of_trash);
49 }
50 private:
51 // garbage must be declared before lock
52 // to insure it is destroyed after lock is
53 // destroyed.
54 auto_buffer<shared_ptr<void>, store_n_objects<10> > garbage;
55 unique_lock<Mutex> lock;
56 };
57
58 class connection_body_base
59 {
60 public:
61 connection_body_base():
62 _connected(true), m_slot_refcount(1)
63 {
64 }
65 virtual ~connection_body_base() {}
66 void disconnect()
67 {
68 garbage_collecting_lock<connection_body_base> local_lock(*this);
69 nolock_disconnect(local_lock);
70 }
71 template<typename Mutex>
72 void nolock_disconnect(garbage_collecting_lock<Mutex> &lock_arg) const
73 {
74 if(_connected)
75 {
76 _connected = false;
77 dec_slot_refcount(lock_arg);
78 }
79 }
80 virtual bool connected() const = 0;
81 shared_ptr<void> get_blocker()
82 {
83 unique_lock<connection_body_base> local_lock(*this);
84 shared_ptr<void> blocker = _weak_blocker.lock();
85 if(blocker == shared_ptr<void>())
86 {
87 blocker.reset(this, &null_deleter);
88 _weak_blocker = blocker;
89 }
90 return blocker;
91 }
92 bool blocked() const
93 {
94 return !_weak_blocker.expired();
95 }
96 bool nolock_nograb_blocked() const
97 {
98 return nolock_nograb_connected() == false || blocked();
99 }
100 bool nolock_nograb_connected() const {return _connected;}
101 // expose part of Lockable concept of mutex
102 virtual void lock() = 0;
103 virtual void unlock() = 0;
104
105 // Slot refcount should be incremented while
106 // a signal invocation is using the slot, in order
107 // to prevent slot from being destroyed mid-invocation.
108 // garbage_collecting_lock parameter enforces
109 // the existance of a lock before this
110 // method is called
111 template<typename Mutex>
112 void inc_slot_refcount(const garbage_collecting_lock<Mutex> &)
113 {
114 BOOST_ASSERT(m_slot_refcount != 0);
115 ++m_slot_refcount;
116 }
117 // if slot refcount decrements to zero due to this call,
118 // it puts a
119 // shared_ptr to the slot in the garbage collecting lock,
120 // which will destroy the slot only after it unlocks.
121 template<typename Mutex>
122 void dec_slot_refcount(garbage_collecting_lock<Mutex> &lock_arg) const
123 {
124 BOOST_ASSERT(m_slot_refcount != 0);
125 if(--m_slot_refcount == 0)
126 {
127 lock_arg.add_trash(release_slot());
128 }
129 }
130
131 protected:
132 virtual shared_ptr<void> release_slot() const = 0;
133
134 weak_ptr<void> _weak_blocker;
135 private:
136 mutable bool _connected;
137 mutable unsigned m_slot_refcount;
138 };
139
140 template<typename GroupKey, typename SlotType, typename Mutex>
141 class connection_body: public connection_body_base
142 {
143 public:
144 typedef Mutex mutex_type;
145 connection_body(const SlotType &slot_in, const boost::shared_ptr<mutex_type> &signal_mutex):
146 m_slot(new SlotType(slot_in)), _mutex(signal_mutex)
147 {
148 }
149 virtual ~connection_body() {}
150 virtual bool connected() const
151 {
152 garbage_collecting_lock<mutex_type> local_lock(*_mutex);
153 nolock_grab_tracked_objects(local_lock, detail::null_output_iterator());
154 return nolock_nograb_connected();
155 }
156 const GroupKey& group_key() const {return _group_key;}
157 void set_group_key(const GroupKey &key) {_group_key = key;}
158 template<typename M>
159 void disconnect_expired_slot(garbage_collecting_lock<M> &lock_arg)
160 {
161 if(!m_slot) return;
162 bool expired = slot().expired();
163 if(expired == true)
164 {
165 nolock_disconnect(lock_arg);
166 }
167 }
168 template<typename M, typename OutputIterator>
169 void nolock_grab_tracked_objects(garbage_collecting_lock<M> &lock_arg,
170 OutputIterator inserter) const
171 {
172 if(!m_slot) return;
173 slot_base::tracked_container_type::const_iterator it;
174 for(it = slot().tracked_objects().begin();
175 it != slot().tracked_objects().end();
176 ++it)
177 {
178 void_shared_ptr_variant locked_object
179 (
180 apply_visitor
181 (
182 detail::lock_weak_ptr_visitor(),
183 *it
184 )
185 );
186 if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))
187 {
188 nolock_disconnect(lock_arg);
189 return;
190 }
191 *inserter++ = locked_object;
192 }
193 }
194 // expose Lockable concept of mutex
195 virtual void lock()
196 {
197 _mutex->lock();
198 }
199 virtual void unlock()
200 {
201 _mutex->unlock();
202 }
203 SlotType &slot()
204 {
205 return *m_slot;
206 }
207 const SlotType &slot() const
208 {
209 return *m_slot;
210 }
211 protected:
212 virtual shared_ptr<void> release_slot() const
213 {
214
215 shared_ptr<void> released_slot = m_slot;
216 m_slot.reset();
217 return released_slot;
218 }
219 private:
220 mutable boost::shared_ptr<SlotType> m_slot;
221 const boost::shared_ptr<mutex_type> _mutex;
222 GroupKey _group_key;
223 };
224 }
225
226 class shared_connection_block;
227
228 class connection
229 {
230 public:
231 friend class shared_connection_block;
232
233 connection() BOOST_NOEXCEPT {}
234 connection(const connection &other) BOOST_NOEXCEPT: _weak_connection_body(other._weak_connection_body)
235 {}
236 connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody) BOOST_NOEXCEPT:
237 _weak_connection_body(connectionBody)
238 {}
239
240 // move support
241 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
242 connection(connection && other) BOOST_NOEXCEPT: _weak_connection_body(std::move(other._weak_connection_body))
243 {
244 // make sure other is reset, in case it is a scoped_connection (so it
245 // won't disconnect on destruction after being moved away from).
246 other._weak_connection_body.reset();
247 }
248 connection & operator=(connection && other) BOOST_NOEXCEPT
249 {
250 if(&other == this) return *this;
251 _weak_connection_body = std::move(other._weak_connection_body);
252 // make sure other is reset, in case it is a scoped_connection (so it
253 // won't disconnect on destruction after being moved away from).
254 other._weak_connection_body.reset();
255 return *this;
256 }
257 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
258 connection & operator=(const connection & other) BOOST_NOEXCEPT
259 {
260 if(&other == this) return *this;
261 _weak_connection_body = other._weak_connection_body;
262 return *this;
263 }
264
265 ~connection() {}
266 void disconnect() const
267 {
268 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
269 if(connectionBody == 0) return;
270 connectionBody->disconnect();
271 }
272 bool connected() const
273 {
274 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
275 if(connectionBody == 0) return false;
276 return connectionBody->connected();
277 }
278 bool blocked() const
279 {
280 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
281 if(connectionBody == 0) return true;
282 return connectionBody->blocked();
283 }
284 bool operator==(const connection& other) const
285 {
286 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
287 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
288 return connectionBody == otherConnectionBody;
289 }
290 bool operator!=(const connection& other) const
291 {
292 return !(*this == other);
293 }
294 bool operator<(const connection& other) const
295 {
296 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
297 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
298 return connectionBody < otherConnectionBody;
299 }
300 void swap(connection &other) BOOST_NOEXCEPT
301 {
302 using std::swap;
303 swap(_weak_connection_body, other._weak_connection_body);
304 }
305 protected:
306
307 boost::weak_ptr<detail::connection_body_base> _weak_connection_body;
308 };
309 inline void swap(connection &conn1, connection &conn2) BOOST_NOEXCEPT
310 {
311 conn1.swap(conn2);
312 }
313
314 class scoped_connection: public connection
315 {
316 public:
317 scoped_connection() BOOST_NOEXCEPT {}
318 scoped_connection(const connection &other) BOOST_NOEXCEPT:
319 connection(other)
320 {}
321 ~scoped_connection()
322 {
323 disconnect();
324 }
325 scoped_connection& operator=(const connection &rhs) BOOST_NOEXCEPT
326 {
327 disconnect();
328 connection::operator=(rhs);
329 return *this;
330 }
331
332 // move support
333 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
334 scoped_connection(scoped_connection && other) BOOST_NOEXCEPT: connection(std::move(other))
335 {
336 }
337 scoped_connection(connection && other) BOOST_NOEXCEPT: connection(std::move(other))
338 {
339 }
340 scoped_connection & operator=(scoped_connection && other) BOOST_NOEXCEPT
341 {
342 if(&other == this) return *this;
343 disconnect();
344 connection::operator=(std::move(other));
345 return *this;
346 }
347 scoped_connection & operator=(connection && other) BOOST_NOEXCEPT
348 {
349 if(&other == this) return *this;
350 disconnect();
351 connection::operator=(std::move(other));
352 return *this;
353 }
354 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
355
356 connection release()
357 {
358 connection conn(_weak_connection_body);
359 _weak_connection_body.reset();
360 return conn;
361 }
362 private:
363 scoped_connection(const scoped_connection &other);
364 scoped_connection& operator=(const scoped_connection &rhs);
365 };
366 // Sun 5.9 compiler doesn't find the swap for base connection class when
367 // arguments are scoped_connection, so we provide this explicitly.
368 inline void swap(scoped_connection &conn1, scoped_connection &conn2) BOOST_NOEXCEPT
369 {
370 conn1.swap(conn2);
371 }
372 }
373 }
374
375 #endif // BOOST_SIGNALS2_CONNECTION_HPP