diff options
Diffstat (limited to 'boost/signals2')
-rw-r--r-- | boost/signals2/connection.hpp | 125 | ||||
-rw-r--r-- | boost/signals2/deconstruct_ptr.hpp | 8 | ||||
-rw-r--r-- | boost/signals2/detail/auto_buffer.hpp | 1 | ||||
-rw-r--r-- | boost/signals2/detail/lwm_win32_cs.hpp | 2 | ||||
-rw-r--r-- | boost/signals2/detail/signal_template.hpp | 109 | ||||
-rw-r--r-- | boost/signals2/detail/slot_call_iterator.hpp | 67 | ||||
-rw-r--r-- | boost/signals2/detail/variadic_slot_invoker.hpp | 33 | ||||
-rw-r--r-- | boost/signals2/last_value.hpp | 5 | ||||
-rw-r--r-- | boost/signals2/preprocessed_signal.hpp | 2 | ||||
-rw-r--r-- | boost/signals2/signal.hpp | 1 | ||||
-rw-r--r-- | boost/signals2/slot_base.hpp | 3 | ||||
-rw-r--r-- | boost/signals2/variadic_signal.hpp | 2 |
12 files changed, 240 insertions, 118 deletions
diff --git a/boost/signals2/connection.hpp b/boost/signals2/connection.hpp index 0ab4dacbf6..dac806b221 100644 --- a/boost/signals2/connection.hpp +++ b/boost/signals2/connection.hpp @@ -18,6 +18,7 @@ #include <boost/mpl/bool.hpp> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> +#include <boost/signals2/detail/auto_buffer.hpp> #include <boost/signals2/detail/null_output_iterator.hpp> #include <boost/signals2/detail/unique_lock.hpp> #include <boost/signals2/slot.hpp> @@ -27,25 +28,53 @@ namespace boost { namespace signals2 { - extern inline void null_deleter(const void*) {} + inline void null_deleter(const void*) {} namespace detail { + // This lock maintains a list of shared_ptr<void> + // which will be destroyed only after the lock + // has released its mutex. Used to garbage + // collect disconnected slots + template<typename Mutex> + class garbage_collecting_lock: public noncopyable + { + public: + garbage_collecting_lock(Mutex &m): + lock(m) + {} + void add_trash(const shared_ptr<void> &piece_of_trash) + { + garbage.push_back(piece_of_trash); + } + private: + // garbage must be declared before lock + // to insure it is destroyed after lock is + // destroyed. + auto_buffer<shared_ptr<void>, store_n_objects<10> > garbage; + unique_lock<Mutex> lock; + }; + class connection_body_base { public: connection_body_base(): - _connected(true) + _connected(true), m_slot_refcount(1) { } virtual ~connection_body_base() {} void disconnect() { - unique_lock<connection_body_base> local_lock(*this); - nolock_disconnect(); + garbage_collecting_lock<connection_body_base> local_lock(*this); + nolock_disconnect(local_lock); } - void nolock_disconnect() + template<typename Mutex> + void nolock_disconnect(garbage_collecting_lock<Mutex> &lock_arg) const { - _connected = false; + if(_connected) + { + _connected = false; + dec_slot_refcount(lock_arg); + } } virtual bool connected() const = 0; shared_ptr<void> get_blocker() @@ -72,10 +101,39 @@ namespace boost virtual void lock() = 0; virtual void unlock() = 0; + // Slot refcount should be incremented while + // a signal invocation is using the slot, in order + // to prevent slot from being destroyed mid-invocation. + // garbage_collecting_lock parameter enforces + // the existance of a lock before this + // method is called + template<typename Mutex> + void inc_slot_refcount(const garbage_collecting_lock<Mutex> &) + { + BOOST_ASSERT(m_slot_refcount != 0); + ++m_slot_refcount; + } + // if slot refcount decrements to zero due to this call, + // it puts a + // shared_ptr to the slot in the garbage collecting lock, + // which will destroy the slot only after it unlocks. + template<typename Mutex> + void dec_slot_refcount(garbage_collecting_lock<Mutex> &lock_arg) const + { + BOOST_ASSERT(m_slot_refcount != 0); + if(--m_slot_refcount == 0) + { + lock_arg.add_trash(release_slot()); + } + } + protected: + virtual shared_ptr<void> release_slot() const = 0; - mutable bool _connected; weak_ptr<void> _weak_blocker; + private: + mutable bool _connected; + mutable unsigned m_slot_refcount; }; template<typename GroupKey, typename SlotType, typename Mutex> @@ -83,34 +141,37 @@ namespace boost { public: typedef Mutex mutex_type; - connection_body(const SlotType &slot_in): - slot(slot_in) + connection_body(const SlotType &slot_in, const boost::shared_ptr<mutex_type> &signal_mutex): + m_slot(new SlotType(slot_in)), _mutex(signal_mutex) { } virtual ~connection_body() {} virtual bool connected() const { - unique_lock<mutex_type> local_lock(_mutex); - nolock_grab_tracked_objects(detail::null_output_iterator()); + garbage_collecting_lock<mutex_type> local_lock(*_mutex); + nolock_grab_tracked_objects(local_lock, detail::null_output_iterator()); return nolock_nograb_connected(); } const GroupKey& group_key() const {return _group_key;} void set_group_key(const GroupKey &key) {_group_key = key;} - bool nolock_slot_expired() const + template<typename M> + void disconnect_expired_slot(garbage_collecting_lock<M> &lock_arg) { - bool expired = slot.expired(); + if(!m_slot) return; + bool expired = slot().expired(); if(expired == true) { - _connected = false; + nolock_disconnect(lock_arg); } - return expired; } - template<typename OutputIterator> - void nolock_grab_tracked_objects(OutputIterator inserter) const + template<typename M, typename OutputIterator> + void nolock_grab_tracked_objects(garbage_collecting_lock<M> &lock_arg, + OutputIterator inserter) const { + if(!m_slot) return; slot_base::tracked_container_type::const_iterator it; - for(it = slot.tracked_objects().begin(); - it != slot.tracked_objects().end(); + for(it = slot().tracked_objects().begin(); + it != slot().tracked_objects().end(); ++it) { void_shared_ptr_variant locked_object @@ -123,7 +184,7 @@ namespace boost ); if(apply_visitor(detail::expired_weak_ptr_visitor(), *it)) { - _connected = false; + nolock_disconnect(lock_arg); return; } *inserter++ = locked_object; @@ -132,15 +193,31 @@ namespace boost // expose Lockable concept of mutex virtual void lock() { - _mutex.lock(); + _mutex->lock(); } virtual void unlock() { - _mutex.unlock(); + _mutex->unlock(); + } + SlotType &slot() + { + return *m_slot; + } + const SlotType &slot() const + { + return *m_slot; + } + protected: + virtual shared_ptr<void> release_slot() const + { + + shared_ptr<void> released_slot = m_slot; + m_slot.reset(); + return released_slot; } - SlotType slot; private: - mutable mutex_type _mutex; + mutable boost::shared_ptr<SlotType> m_slot; + const boost::shared_ptr<mutex_type> _mutex; GroupKey _group_key; }; } diff --git a/boost/signals2/deconstruct_ptr.hpp b/boost/signals2/deconstruct_ptr.hpp index 841b19b2c1..bdc11188ee 100644 --- a/boost/signals2/deconstruct_ptr.hpp +++ b/boost/signals2/deconstruct_ptr.hpp @@ -27,18 +27,18 @@ namespace boost { namespace detail { - extern inline void do_postconstruct(const postconstructible *ptr) + inline void do_postconstruct(const postconstructible *ptr) { postconstructible *nonconst_ptr = const_cast<postconstructible*>(ptr); nonconst_ptr->postconstruct(); } - extern inline void do_postconstruct(...) + inline void do_postconstruct(...) { } - extern inline void do_predestruct(...) + inline void do_predestruct(...) { } - extern inline void do_predestruct(const predestructible *ptr) + inline void do_predestruct(const predestructible *ptr) { try { diff --git a/boost/signals2/detail/auto_buffer.hpp b/boost/signals2/detail/auto_buffer.hpp index bf12e698e2..8007b3c6b9 100644 --- a/boost/signals2/detail/auto_buffer.hpp +++ b/boost/signals2/detail/auto_buffer.hpp @@ -23,7 +23,6 @@ #include <boost/mpl/if.hpp> #include <boost/multi_index/detail/scope_guard.hpp> #include <boost/swap.hpp> -#include <boost/throw_exception.hpp> #include <boost/type_traits/aligned_storage.hpp> #include <boost/type_traits/alignment_of.hpp> #include <boost/type_traits/has_nothrow_copy.hpp> diff --git a/boost/signals2/detail/lwm_win32_cs.hpp b/boost/signals2/detail/lwm_win32_cs.hpp index d1c1965dea..462da03174 100644 --- a/boost/signals2/detail/lwm_win32_cs.hpp +++ b/boost/signals2/detail/lwm_win32_cs.hpp @@ -55,7 +55,7 @@ extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSectionEx(crit extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(critical_section *); #endif extern "C" __declspec(dllimport) void __stdcall EnterCriticalSection(critical_section *); -extern "C" __declspec(dllimport) bool __stdcall TryEnterCriticalSection(critical_section *); +extern "C" __declspec(dllimport) int __stdcall TryEnterCriticalSection(critical_section *); extern "C" __declspec(dllimport) void __stdcall LeaveCriticalSection(critical_section *); extern "C" __declspec(dllimport) void __stdcall DeleteCriticalSection(critical_section *); diff --git a/boost/signals2/detail/signal_template.hpp b/boost/signals2/detail/signal_template.hpp index 09d7d8d9f9..d3adcee6bc 100644 --- a/boost/signals2/detail/signal_template.hpp +++ b/boost/signals2/detail/signal_template.hpp @@ -154,37 +154,38 @@ namespace boost BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg, const group_compare_type &group_compare): _shared_state(new invocation_state(connection_list_type(group_compare), combiner_arg)), - _garbage_collector_it(_shared_state->connection_bodies().end()) + _garbage_collector_it(_shared_state->connection_bodies().end()), + _mutex(new mutex_type()) {} // connect slot connection connect(const slot_type &slot, connect_position position = at_back) { - unique_lock<mutex_type> lock(_mutex); - return nolock_connect(slot, position); + garbage_collecting_lock<mutex_type> lock(*_mutex); + return nolock_connect(lock, slot, position); } connection connect(const group_type &group, const slot_type &slot, connect_position position = at_back) { - unique_lock<Mutex> lock(_mutex); - return nolock_connect(group, slot, position); + garbage_collecting_lock<mutex_type> lock(*_mutex); + return nolock_connect(lock, group, slot, position); } // connect extended slot connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back) { - unique_lock<mutex_type> lock(_mutex); + garbage_collecting_lock<mutex_type> lock(*_mutex); bound_extended_slot_function_type bound_slot(ext_slot.slot_function()); slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot); - connection conn = nolock_connect(slot, position); + connection conn = nolock_connect(lock, slot, position); bound_slot.set_connection(conn); return conn; } connection connect_extended(const group_type &group, const extended_slot_type &ext_slot, connect_position position = at_back) { - unique_lock<Mutex> lock(_mutex); + garbage_collecting_lock<Mutex> lock(*_mutex); bound_extended_slot_function_type bound_slot(ext_slot.slot_function()); slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot); - connection conn = nolock_connect(group, slot, position); + connection conn = nolock_connect(lock, group, slot, position); bound_slot.set_connection(conn); return conn; } @@ -226,10 +227,10 @@ namespace boost shared_ptr<invocation_state> local_state; typename connection_list_type::iterator it; { - unique_lock<mutex_type> list_lock(_mutex); + garbage_collecting_lock<mutex_type> list_lock(*_mutex); // only clean up if it is safe to do so if(_shared_state.unique()) - nolock_cleanup_connections(false, 1); + nolock_cleanup_connections(list_lock, false, 1); /* Make a local copy of _shared_state while holding mutex, so we are thread safe against the combiner or connection list getting modified during invocation. */ @@ -250,10 +251,10 @@ namespace boost shared_ptr<invocation_state> local_state; typename connection_list_type::iterator it; { - unique_lock<mutex_type> list_lock(_mutex); + garbage_collecting_lock<mutex_type> list_lock(*_mutex); // only clean up if it is safe to do so if(_shared_state.unique()) - nolock_cleanup_connections(false, 1); + nolock_cleanup_connections(list_lock, false, 1); /* Make a local copy of _shared_state while holding mutex, so we are thread safe against the combiner or connection list getting modified during invocation. */ @@ -296,12 +297,12 @@ namespace boost } combiner_type combiner() const { - unique_lock<mutex_type> lock(_mutex); + unique_lock<mutex_type> lock(*_mutex); return _shared_state->combiner(); } void set_combiner(const combiner_type &combiner_arg) { - unique_lock<mutex_type> lock(_mutex); + unique_lock<mutex_type> lock(*_mutex); if(_shared_state.unique()) _shared_state->combiner() = combiner_arg; else @@ -340,9 +341,7 @@ namespace boost {} result_type operator ()(const connection_body_type &connectionBody) const { - result_type *resolver = 0; - return m_invoke(connectionBody, - resolver); + return m_invoke<typename slot_type::result_type>(connectionBody); } private: // declare assignment operator private since this class might have reference or const members @@ -357,15 +356,18 @@ namespace boost // m_arg1, m_arg2, ..., m_argn #define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~) + template<typename SlotResultType> result_type m_invoke(const connection_body_type &connectionBody, - const void_type *) const + typename boost::enable_if<boost::is_void<SlotResultType> >::type * = 0) const { - connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); + connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); return void_type(); } - result_type m_invoke(const connection_body_type &connectionBody, ...) const + template<typename SlotResultType> + result_type m_invoke(const connection_body_type &connectionBody, + typename boost::disable_if<boost::is_void<SlotResultType> >::type * = 0) const { - return connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); + return connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); } }; #undef BOOST_SIGNALS2_M_ARG_NAMES @@ -427,7 +429,8 @@ namespace boost }; // clean up disconnected connections - void nolock_cleanup_connections_from(bool grab_tracked, + void nolock_cleanup_connections_from(garbage_collecting_lock<mutex_type> &lock, + bool grab_tracked, const typename connection_list_type::iterator &begin, unsigned count = 0) const { BOOST_ASSERT(_shared_state.unique()); @@ -438,12 +441,9 @@ namespace boost ++i) { bool connected; - { - unique_lock<connection_body_base> lock(**it); - if(grab_tracked) - (*it)->nolock_slot_expired(); - connected = (*it)->nolock_nograb_connected(); - }// scoped lock destructs here, safe to erase now + if(grab_tracked) + (*it)->disconnect_expired_slot(lock); + connected = (*it)->nolock_nograb_connected(); if(connected == false) { it = _shared_state->connection_bodies().erase((*it)->group_key(), it); @@ -455,7 +455,8 @@ namespace boost _garbage_collector_it = it; } // clean up a few connections in constant time - void nolock_cleanup_connections(bool grab_tracked, unsigned count) const + void nolock_cleanup_connections(garbage_collecting_lock<mutex_type> &lock, + bool grab_tracked, unsigned count) const { BOOST_ASSERT(_shared_state.unique()); typename connection_list_type::iterator begin; @@ -466,28 +467,28 @@ namespace boost { begin = _garbage_collector_it; } - nolock_cleanup_connections_from(grab_tracked, begin, count); + nolock_cleanup_connections_from(lock, grab_tracked, begin, count); } /* Make a new copy of the slot list if it is currently being read somewhere else */ - void nolock_force_unique_connection_list() + void nolock_force_unique_connection_list(garbage_collecting_lock<mutex_type> &lock) { if(_shared_state.unique() == false) { _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies())); - nolock_cleanup_connections_from(true, _shared_state->connection_bodies().begin()); + nolock_cleanup_connections_from(lock, true, _shared_state->connection_bodies().begin()); }else { /* We need to try and check more than just 1 connection here to avoid corner cases where certain repeated connect/disconnect patterns cause the slot list to grow without limit. */ - nolock_cleanup_connections(true, 2); + nolock_cleanup_connections(lock, true, 2); } } // force a full cleanup of the connection list void force_cleanup_connections(const connection_list_type *connection_bodies) const { - unique_lock<mutex_type> list_lock(_mutex); + garbage_collecting_lock<mutex_type> list_lock(*_mutex); // if the connection list passed in as a parameter is no longer in use, // we don't need to do any cleanup. if(&_shared_state->connection_bodies() != connection_bodies) @@ -498,17 +499,18 @@ namespace boost { _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies())); } - nolock_cleanup_connections_from(false, _shared_state->connection_bodies().begin()); + nolock_cleanup_connections_from(list_lock, false, _shared_state->connection_bodies().begin()); } shared_ptr<invocation_state> get_readable_state() const { - unique_lock<mutex_type> list_lock(_mutex); + unique_lock<mutex_type> list_lock(*_mutex); return _shared_state; } - connection_body_type create_new_connection(const slot_type &slot) + connection_body_type create_new_connection(garbage_collecting_lock<mutex_type> &lock, + const slot_type &slot) { - nolock_force_unique_connection_list(); - return connection_body_type(new connection_body<group_key_type, slot_type, Mutex>(slot)); + nolock_force_unique_connection_list(lock); + return connection_body_type(new connection_body<group_key_type, slot_type, Mutex>(slot, _mutex)); } void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */) { @@ -523,27 +525,29 @@ namespace boost for(it = local_state->connection_bodies().begin(); it != local_state->connection_bodies().end(); ++it) { - unique_lock<connection_body_base> lock(**it); - if((*it)->slot.slot_function() == slot) + garbage_collecting_lock<connection_body_base> lock(**it); + if((*it)->nolock_nograb_connected() == false) continue; + if((*it)->slot().slot_function() == slot) { - (*it)->nolock_disconnect(); + (*it)->nolock_disconnect(lock); }else { // check for wrapped extended slot bound_extended_slot_function_type *fp; - fp = (*it)->slot.slot_function().template target<bound_extended_slot_function_type>(); + fp = (*it)->slot().slot_function().template target<bound_extended_slot_function_type>(); if(fp && *fp == slot) { - (*it)->nolock_disconnect(); + (*it)->nolock_disconnect(lock); } } } } // connect slot - connection nolock_connect(const slot_type &slot, connect_position position) + connection nolock_connect(garbage_collecting_lock<mutex_type> &lock, + const slot_type &slot, connect_position position) { connection_body_type newConnectionBody = - create_new_connection(slot); + create_new_connection(lock, slot); group_key_type group_key; if(position == at_back) { @@ -557,11 +561,12 @@ namespace boost newConnectionBody->set_group_key(group_key); return connection(newConnectionBody); } - connection nolock_connect(const group_type &group, + connection nolock_connect(garbage_collecting_lock<mutex_type> &lock, + const group_type &group, const slot_type &slot, connect_position position) { connection_body_type newConnectionBody = - create_new_connection(slot); + create_new_connection(lock, slot); // update map to first connection body in group if needed group_key_type group_key(grouped_slots, group); newConnectionBody->set_group_key(group_key); @@ -580,7 +585,7 @@ namespace boost mutable typename connection_list_type::iterator _garbage_collector_it; // connection list mutex must never be locked when attempting a blocking lock on a slot, // or you could deadlock. - mutable mutex_type _mutex; + const boost::shared_ptr<mutex_type> _mutex; }; template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> @@ -789,7 +794,7 @@ namespace boost shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > shared_pimpl(_weak_pimpl.lock()); - if(shared_pimpl == 0) boost::throw_exception(expired_slot()); + if(shared_pimpl == 0) throw expired_slot(); return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); } result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const @@ -797,7 +802,7 @@ namespace boost shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > shared_pimpl(_weak_pimpl.lock()); - if(shared_pimpl == 0) boost::throw_exception(expired_slot()); + if(shared_pimpl == 0) throw expired_slot(); return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); } private: diff --git a/boost/signals2/detail/slot_call_iterator.hpp b/boost/signals2/detail/slot_call_iterator.hpp index 9dbbb3c9b5..ee8426f474 100644 --- a/boost/signals2/detail/slot_call_iterator.hpp +++ b/boost/signals2/detail/slot_call_iterator.hpp @@ -21,6 +21,8 @@ #include <boost/signals2/slot_base.hpp> #include <boost/signals2/detail/auto_buffer.hpp> #include <boost/signals2/detail/unique_lock.hpp> +#include <boost/type_traits/add_const.hpp> +#include <boost/type_traits/add_reference.hpp> #include <boost/weak_ptr.hpp> namespace boost { @@ -33,14 +35,37 @@ namespace boost { slot_call_iterator_cache(const Function &f_arg): f(f_arg), connected_slot_count(0), - disconnected_slot_count(0) + disconnected_slot_count(0), + m_active_slot(0) {} + + ~slot_call_iterator_cache() + { + if(m_active_slot) + { + garbage_collecting_lock<connection_body_base> lock(*m_active_slot); + m_active_slot->dec_slot_refcount(lock); + } + } + + template<typename M> + void set_active_slot(garbage_collecting_lock<M> &lock, + connection_body_base *active_slot) + { + if(m_active_slot) + m_active_slot->dec_slot_refcount(lock); + m_active_slot = active_slot; + if(m_active_slot) + m_active_slot->inc_slot_refcount(lock); + } + optional<ResultType> result; typedef auto_buffer<void_shared_ptr_variant, store_n_objects<10> > tracked_ptrs_type; tracked_ptrs_type tracked_ptrs; Function f; unsigned connected_slot_count; unsigned disconnected_slot_count; + connection_body_base *m_active_slot; }; // Generates a slot call iterator. Essentially, this is an iterator that: @@ -52,21 +77,23 @@ namespace boost { : public boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, typename Function::result_type, boost::single_pass_traversal_tag, - typename Function::result_type const&> + typename boost::add_const<typename boost::add_reference<typename Function::result_type>::type>::type > { typedef boost::iterator_facade<slot_call_iterator_t<Function, Iterator, ConnectionBody>, typename Function::result_type, boost::single_pass_traversal_tag, - typename Function::result_type const&> + typename boost::add_const<typename boost::add_reference<typename Function::result_type>::type>::type > inherited; typedef typename Function::result_type result_type; + typedef slot_call_iterator_cache<result_type, Function> cache_type; + friend class boost::iterator_core_access; public: slot_call_iterator_t(Iterator iter_in, Iterator end_in, - slot_call_iterator_cache<result_type, Function> &c): + cache_type &c): iter(iter_in), end(end_in), cache(&c), callable_iter(end_in) { @@ -103,19 +130,39 @@ namespace boost { } private: - typedef unique_lock<connection_body_base> lock_type; + typedef garbage_collecting_lock<connection_body_base> lock_type; + void set_callable_iter(lock_type &lock, Iterator newValue) const + { + callable_iter = newValue; + if(callable_iter == end) + cache->set_active_slot(lock, 0); + else + cache->set_active_slot(lock, (*callable_iter).get()); + } + void lock_next_callable() const { if(iter == callable_iter) { return; } + if(iter == end) + { + if(callable_iter != end) + { + lock_type lock(**callable_iter); + set_callable_iter(lock, end); + return; + } + } + // we're only locking the first connection body, + // but it doesn't matter they all use the same mutex + lock_type lock(**iter); for(;iter != end; ++iter) { cache->tracked_ptrs.clear(); - lock_type lock(**iter); - (*iter)->nolock_grab_tracked_objects(std::back_inserter(cache->tracked_ptrs)); + (*iter)->nolock_grab_tracked_objects(lock, std::back_inserter(cache->tracked_ptrs)); if((*iter)->nolock_nograb_connected()) { ++cache->connected_slot_count; @@ -125,19 +172,19 @@ namespace boost { } if((*iter)->nolock_nograb_blocked() == false) { - callable_iter = iter; + set_callable_iter(lock, iter); break; } } if(iter == end) { - callable_iter = end; + set_callable_iter(lock, end); } } mutable Iterator iter; Iterator end; - slot_call_iterator_cache<result_type, Function> *cache; + cache_type *cache; mutable Iterator callable_iter; }; } // end namespace detail diff --git a/boost/signals2/detail/variadic_slot_invoker.hpp b/boost/signals2/detail/variadic_slot_invoker.hpp index cab331eb1c..c115a63df5 100644 --- a/boost/signals2/detail/variadic_slot_invoker.hpp +++ b/boost/signals2/detail/variadic_slot_invoker.hpp @@ -77,17 +77,20 @@ namespace boost R operator()(Func &func, BOOST_SIGNALS2_TUPLE<Args...> args, mpl::size_t<N>) const { typedef typename make_unsigned_meta_array<N>::type indices_type; - typename Func::result_type *resolver = 0; - return m_invoke(resolver, func, indices_type(), args); + return m_invoke<Func>(func, indices_type(), args); } private: - template<typename T, typename Func, unsigned ... indices, typename ... Args> - R m_invoke(T *, Func &func, unsigned_meta_array<indices...>, BOOST_SIGNALS2_TUPLE<Args...> args) const + template<typename Func, unsigned ... indices, typename ... Args> + R m_invoke(Func &func, unsigned_meta_array<indices...>, BOOST_SIGNALS2_TUPLE<Args...> args, + typename boost::disable_if<boost::is_void<typename Func::result_type> >::type * = 0 + ) const { return func(BOOST_SIGNALS2_GET<indices>(args)...); } template<typename Func, unsigned ... indices, typename ... Args> - R m_invoke(void *, Func &func, unsigned_meta_array<indices...>, BOOST_SIGNALS2_TUPLE<Args...> args) const + R m_invoke(Func &func, unsigned_meta_array<indices...>, BOOST_SIGNALS2_TUPLE<Args...> args, + typename boost::enable_if<boost::is_void<typename Func::result_type> >::type * = 0 + ) const { func(BOOST_SIGNALS2_GET<indices>(args)...); return R(); @@ -97,7 +100,9 @@ namespace boost // only exists to quiet some unused parameter warnings // on certain compilers (some versions of gcc and msvc) template<typename Func> - R m_invoke(void *, Func &func, unsigned_meta_array<>, BOOST_SIGNALS2_TUPLE<>) const + R m_invoke(Func &func, unsigned_meta_array<>, BOOST_SIGNALS2_TUPLE<>, + typename boost::enable_if<boost::is_void<typename Func::result_type> >::type * = 0 + ) const { func(); return R(); @@ -115,22 +120,10 @@ namespace boost template<typename ConnectionBodyType> result_type operator ()(const ConnectionBodyType &connectionBody) const { - result_type *resolver = 0; - return m_invoke(connectionBody, - resolver); + return call_with_tuple_args<result_type>()(connectionBody->slot().slot_function(), + _args, mpl::size_t<sizeof...(Args)>()); } private: - template<typename ConnectionBodyType> - result_type m_invoke(const ConnectionBodyType &connectionBody, - const void_type *) const - { - return call_with_tuple_args<result_type>()(connectionBody->slot.slot_function(), _args, mpl::size_t<sizeof...(Args)>()); - } - template<typename ConnectionBodyType> - result_type m_invoke(const ConnectionBodyType &connectionBody, ...) const - { - return call_with_tuple_args<result_type>()(connectionBody->slot.slot_function(), _args, mpl::size_t<sizeof...(Args)>()); - } BOOST_SIGNALS2_TUPLE<Args& ...> _args; }; } // namespace detail diff --git a/boost/signals2/last_value.hpp b/boost/signals2/last_value.hpp index 51cc541a4e..c5d5f33b21 100644 --- a/boost/signals2/last_value.hpp +++ b/boost/signals2/last_value.hpp @@ -13,7 +13,6 @@ #include <boost/optional.hpp> #include <boost/signals2/expired_slot.hpp> -#include <boost/throw_exception.hpp> #include <stdexcept> namespace boost { @@ -37,7 +36,7 @@ namespace boost { { if(first == last) { - boost::throw_exception(no_slots_error()); + throw no_slots_error(); } optional<T> value; while (first != last) @@ -50,7 +49,7 @@ namespace boost { ++first; } if(value) return value.get(); - boost::throw_exception(no_slots_error()); + throw no_slots_error(); } }; diff --git a/boost/signals2/preprocessed_signal.hpp b/boost/signals2/preprocessed_signal.hpp index 28471ba4ae..794c1be67e 100644 --- a/boost/signals2/preprocessed_signal.hpp +++ b/boost/signals2/preprocessed_signal.hpp @@ -22,6 +22,8 @@ #include <boost/preprocessor/repetition.hpp> #include <boost/signals2/detail/preprocessed_arg_type.hpp> #include <boost/type_traits/add_reference.hpp> +#include <boost/type_traits/is_void.hpp> +#include <boost/utility/enable_if.hpp> #define BOOST_PP_ITERATION_LIMITS (0, BOOST_SIGNALS2_MAX_ARGS) #define BOOST_PP_FILENAME_1 <boost/signals2/detail/signal_template.hpp> diff --git a/boost/signals2/signal.hpp b/boost/signals2/signal.hpp index 7abcea6241..afdfa66343 100644 --- a/boost/signals2/signal.hpp +++ b/boost/signals2/signal.hpp @@ -30,7 +30,6 @@ #include <boost/signals2/optional_last_value.hpp> #include <boost/signals2/mutex.hpp> #include <boost/signals2/slot.hpp> -#include <boost/throw_exception.hpp> #include <functional> #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES diff --git a/boost/signals2/slot_base.hpp b/boost/signals2/slot_base.hpp index e297180e49..0dd80db146 100644 --- a/boost/signals2/slot_base.hpp +++ b/boost/signals2/slot_base.hpp @@ -17,7 +17,6 @@ #include <boost/signals2/detail/foreign_ptr.hpp> #include <boost/signals2/expired_slot.hpp> #include <boost/signals2/signal_base.hpp> -#include <boost/throw_exception.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/variant.hpp> #include <vector> @@ -77,7 +76,7 @@ namespace boost locked_objects.push_back(apply_visitor(detail::lock_weak_ptr_visitor(), *it)); if(apply_visitor(detail::expired_weak_ptr_visitor(), *it)) { - boost::throw_exception(expired_slot()); + throw expired_slot(); } } return locked_objects; diff --git a/boost/signals2/variadic_signal.hpp b/boost/signals2/variadic_signal.hpp index d7d26193a6..8cd81f7a59 100644 --- a/boost/signals2/variadic_signal.hpp +++ b/boost/signals2/variadic_signal.hpp @@ -20,6 +20,8 @@ #include <boost/signals2/detail/variadic_arg_type.hpp> #include <boost/signals2/detail/variadic_slot_invoker.hpp> #include <boost/type_traits/function_traits.hpp> +#include <boost/type_traits/is_void.hpp> +#include <boost/utility/enable_if.hpp> namespace boost { |