35 #include <glibmm/threads.h> 
   37 #include <boost/bind/protect.hpp> 
   38 #include <boost/enable_shared_from_this.hpp> 
   46 #define DEBUG_PBD_SIGNAL_CONNECTIONS 
   47 #define DEBUG_PBD_SIGNAL_EMISSION 
   50 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS 
   56 using namespace std::placeholders;
 
   60 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS 
   76         , _debug_connection (false)
 
   79         , _debug_emission (false)
 
   83         virtual void disconnect (std::shared_ptr<Connection>) = 0;
 
   84 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS 
   87 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
   94 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS 
   97 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  108         template <
typename Iter>
 
  111                 while (first != last) {
 
  120 template <
typename Combiner, 
typename _Signature>
 
  123 template <
typename Combiner, 
typename R, 
typename... A>
 
  138         static void compositor (
typename std::function<
void(A...)> f,
 
  159         typename std::conditional_t<std::is_void_v<R>, R, 
typename Combiner::result_type>
 
  164                 return _slots.empty ();
 
  169                 return _slots.size ();
 
  177         void disconnect (std::shared_ptr<Connection> c);
 
  181 template <
typename R>
 
  184 template <
typename _Signature>
 
  187 template <
typename R, 
typename... A>
 
  195                 , _invalidation_record (ir)
 
  197                 if (_invalidation_record) {
 
  198                         _invalidation_record->ref ();
 
  205                 SignalBase* signal = _signal.exchange (0, std::memory_order_acq_rel);
 
  220                 if (_invalidation_record) {
 
  221                         _invalidation_record->unref ();
 
  228                 if (!_signal.exchange (0, std::memory_order_acq_rel)) {
 
  238                 if (_invalidation_record) {
 
  239                         _invalidation_record->unref ();
 
  315 template <
typename Combiner, 
typename R, 
typename... A>
 
  321         event_loop->
call_slot (ir, std::bind (f, a...));
 
  324 template <
typename Combiner, 
typename R, 
typename... A>
 
  327         _in_dtor.store (
true, std::memory_order_release);
 
  330         for (
typename Slots::const_iterator i = _slots.begin(); i != _slots.end(); ++i) {
 
  331                 i->first->signal_going_away ();
 
  342 template <
typename Combiner, 
typename R, 
typename... A>
 
  347         c = _connect (0, slot);
 
  357 template <
typename Combiner, 
typename R, 
typename... A>
 
  390 template <
typename Combiner, 
typename R, 
typename... A>
 
  401         clist.
add_connection (_connect (ir, [slot, event_loop, ir](A... a) {
 
  402                 return compositor(slot, event_loop, ir, a...);
 
  411 template <
typename Combiner, 
typename R, 
typename... A>
 
  422         c = _connect (ir, [slot, event_loop, ir](A... a) {
 
  423                 return compositor(slot, event_loop, ir, a...);
 
  432 template <
typename Combiner, 
typename R, 
typename... A>
 
  433 typename std::conditional_t<std::is_void_v<R>, R, 
typename Combiner::result_type>
 
  436 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  437         if (_debug_emission) {
 
  438                 std::cerr << 
"------ Signal @ " << 
this << 
" emission process begins with " << _slots.size() << std::endl;
 
  453         std::vector<Connection*> s;
 
  455         const std::size_t nslots = 512;
 
  456         std::vector<Connection*,PBD::StackAllocator<Connection*,nslots> > s;
 
  474                 for (
auto const & [connection,functor] : _slots) {
 
  475                         s.push_back (connection.get());
 
  479         if constexpr (std::is_void_v<R>) {
 
  482                 for (
auto const & c : s) {
 
  491                         bool still_there = 
false;
 
  495                                 typename Slots::const_iterator f = std::find_if (_slots.begin(), _slots.end(), [&](
typename Slots::value_type 
const & elem) { return elem.first.get() == c; });
 
  496                                 if (f != _slots.end()) {
 
  503 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  504                                 if (_debug_emission) {
 
  505                                         std::cerr << 
"signal @ " << 
this << 
" calling slot for connection @ " << c << 
" of " << _slots.size() << std::endl;
 
  510 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  511                                 if (_debug_emission) {
 
  512                                         std::cerr << 
"signal @ " << 
this << 
" connection  " << c << 
" of " << _slots.size() << 
" was no longer in the slot list\n";
 
  518 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  519                 if (_debug_emission) {
 
  520                         std::cerr << 
"------ Signal @ " << 
this << 
" emission process ends\n";
 
  527                         return typename Combiner::result_type ();
 
  552                 r.reserve (s.size());
 
  555                 for (
auto const & c : s) {
 
  562                         bool still_there = 
false;
 
  566                                 typename Slots::const_iterator f = std::find_if (_slots.begin(), _slots.end(), [&](
typename Slots::value_type 
const & elem) { return elem.first.get() == c; });
 
  568                                 if (f != _slots.end()) {
 
  574 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  575                                 if (_debug_emission) {
 
  576                                         std::cerr << 
"signal @ " << 
this << 
" calling non-void slot for connection @ " << c << 
" of " << _slots.size() << std::endl;
 
  579                                 r.push_back (functor (a...));
 
  582 #ifdef DEBUG_PBD_SIGNAL_EMISSION 
  583                         if (_debug_emission) {
 
  584                                 std::cerr << 
"------ Signal @ " << 
this << 
" emission process ends\n";
 
  590                 return c (r.begin(), r.end());
 
  594 template <
typename Combiner, 
typename R, 
typename... A>
 
  595 std::shared_ptr<Connection>
 
  599         std::shared_ptr<Connection> c (
new Connection (
this, ir));
 
  603 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS 
  607         if (_debug_connection) {
 
  608                 std::cerr << 
"+++++++ CONNECT " << 
this << 
" via connection @ " << c << 
" size now " << _slots.size() << std::endl;
 
  615 template <
typename Combiner, 
typename R, 
typename... A>
 
  621         while (!lm.locked()) {
 
  622                 if (_in_dtor.load (std::memory_order_acquire)) {
 
  633         #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS 
  634         if (_debug_connection) {
 
  635                 std::cerr << 
"------- DISCCONNECT " << 
this << 
" size now " << _slots.size() << std::endl;
 
std::atomic< SignalBase * > _signal
Glib::Threads::Mutex _mutex
PBD::EventLoop::InvalidationRecord * _invalidation_record
Connection(SignalBase *b, PBD::EventLoop::InvalidationRecord *ir)
virtual bool call_slot(InvalidationRecord *, const std::function< void()> &)=0
std::optional< R > result_type
Glib::Threads::Mutex _scoped_connection_lock
std::list< ScopedConnectionList * >::size_type size() const
void add_connection(const UnscopedConnection &c)
ConnectionList _scoped_connection_list
std::list< ScopedConnection * > ConnectionList
virtual ~ScopedConnectionList()
ScopedConnectionList(const ScopedConnectionList &)=delete
ScopedConnection(UnscopedConnection c)
UnscopedConnection const  & the_connection() const
std::atomic< bool > _in_dtor
virtual void disconnect(std::shared_ptr< Connection >)=0
void set_debug_connection(bool yn)
Glib::Threads::Mutex _mutex
void set_debug_emission(bool yn)
std::map< std::shared_ptr< Connection >, slot_function_type > Slots
std::function< R(A...)> slot_function_type
std::shared_ptr< Connection > UnscopedConnection
static std::size_t max_signal_subscribers
void stacktrace(std::ostream &out, int levels=0, size_t start_level=0)
#define DEBUG_PBD_SIGNAL_EMISSION
#define DEBUG_PBD_SIGNAL_CONNECTIONS
PBD::EventLoop * event_loop