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