summaryrefslogtreecommitdiff
path: root/boost/signals2/detail/signal_template.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/signals2/detail/signal_template.hpp')
-rw-r--r--boost/signals2/detail/signal_template.hpp109
1 files changed, 57 insertions, 52 deletions
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: