summaryrefslogtreecommitdiff
path: root/boost/signals2
diff options
context:
space:
mode:
Diffstat (limited to 'boost/signals2')
-rw-r--r--boost/signals2/connection.hpp125
-rw-r--r--boost/signals2/deconstruct_ptr.hpp8
-rw-r--r--boost/signals2/detail/auto_buffer.hpp1
-rw-r--r--boost/signals2/detail/lwm_win32_cs.hpp2
-rw-r--r--boost/signals2/detail/signal_template.hpp109
-rw-r--r--boost/signals2/detail/slot_call_iterator.hpp67
-rw-r--r--boost/signals2/detail/variadic_slot_invoker.hpp33
-rw-r--r--boost/signals2/last_value.hpp5
-rw-r--r--boost/signals2/preprocessed_signal.hpp2
-rw-r--r--boost/signals2/signal.hpp1
-rw-r--r--boost/signals2/slot_base.hpp3
-rw-r--r--boost/signals2/variadic_signal.hpp2
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
{