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\n";
442 const std::size_t nslots = 512;
443 std::vector<Connection*,PBD::StackAllocator<Connection*,nslots> > s;
460 for (
auto const & [connection,functor] : _slots) {
461 s.push_back (connection.get());
465 if constexpr (std::is_void_v<R>) {
468 for (
auto const & c : s) {
477 bool still_there =
false;
481 typename Slots::const_iterator f = std::find_if (_slots.begin(), _slots.end(), [&](
typename Slots::value_type
const & elem) { return elem.first.get() == c; });
482 if (f != _slots.end()) {
489 #ifdef DEBUG_PBD_SIGNAL_EMISSION
490 if (_debug_emission) {
491 std::cerr <<
"signal @ " <<
this <<
" calling slot for connection @ " << c <<
" of " << _slots.size() << std::endl;
498 #ifdef DEBUG_PBD_SIGNAL_EMISSION
499 if (_debug_emission) {
500 std::cerr <<
"------ Signal @ " <<
this <<
" emission process ends\n";
506 std::list<R,PBD::StackAllocator<R,nslots> > r;
509 for (
auto const & c : s) {
516 bool still_there =
false;
520 typename Slots::const_iterator f = std::find_if (_slots.begin(), _slots.end(), [&](
typename Slots::value_type
const & elem) { return elem.first.get() == c; });
522 if (f != _slots.end()) {
528 #ifdef DEBUG_PBD_SIGNAL_EMISSION
529 if (_debug_emission) {
530 std::cerr <<
"signal @ " <<
this <<
" calling non-void slot for connection @ " << c <<
" of " << _slots.size() << std::endl;
533 r.push_back (functor (a...));
536 #ifdef DEBUG_PBD_SIGNAL_EMISSION
537 if (_debug_emission) {
538 std::cerr <<
"------ Signal @ " <<
this <<
" emission process ends\n";
544 return c (r.begin(), r.end());
548 template <
typename Combiner,
typename R,
typename... A>
549 std::shared_ptr<Connection>
553 std::shared_ptr<Connection> c (
new Connection (
this, ir));
557 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
561 if (_debug_connection) {
562 std::cerr <<
"+++++++ CONNECT " <<
this <<
" via connection @ " << c <<
" size now " << _slots.size() << std::endl;
569 template <
typename Combiner,
typename R,
typename... A>
575 while (!lm.locked()) {
576 if (_in_dtor.load (std::memory_order_acquire)) {
587 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
588 if (_debug_connection) {
589 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