re-add TLSF
[ardour.git] / libs / pbd / pbd / signals.h
1 /*
2     Copyright (C) 2009-2012 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __pbd_signals_h__
21 #define __pbd_signals_h__
22
23 #include <csignal>
24
25 #include <list>
26 #include <map>
27
28 #ifdef nil
29 #undef nil
30 #endif
31
32 #include <glibmm/threads.h>
33
34 #include <boost/noncopyable.hpp>
35 #include <boost/bind.hpp>
36 #include <boost/bind/protect.hpp>
37 #include <boost/function.hpp>
38 #include <boost/enable_shared_from_this.hpp>
39 #include <boost/optional.hpp>
40
41 #include "pbd/libpbd_visibility.h"
42 #include "pbd/event_loop.h"
43
44 #ifndef NDEBUG
45 #define DEBUG_PBD_SIGNAL_CONNECTIONS
46 #endif
47
48 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
49 #include "pbd/stacktrace.h"
50 #include <iostream>
51 #endif
52
53 namespace PBD {
54
55 class LIBPBD_API Connection;
56
57 class LIBPBD_API SignalBase
58 {
59 public:
60         SignalBase ()
61 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
62         : _debug_connection (false)
63 #endif
64         {}
65         virtual ~SignalBase () {}
66         virtual void disconnect (boost::shared_ptr<Connection>) = 0;
67 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
68         void set_debug_connection (bool yn) { _debug_connection = yn; }
69 #endif
70
71 protected:
72         mutable Glib::Threads::Mutex _mutex;
73 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
74         bool _debug_connection;
75 #endif
76 };
77
78 class LIBPBD_API Connection : public boost::enable_shared_from_this<Connection>
79 {
80 public:
81         Connection (SignalBase* b) : _signal (b) {}
82
83         void disconnect ()
84         {
85                 Glib::Threads::Mutex::Lock lm (_mutex);
86                 if (_signal) {
87                         _signal->disconnect (shared_from_this ());
88                         _signal = 0;
89                 }
90         }
91
92         void signal_going_away ()
93         {
94                 Glib::Threads::Mutex::Lock lm (_mutex);
95                 _signal = 0;
96         }
97
98 private:
99         Glib::Threads::Mutex _mutex;
100         SignalBase* _signal;
101 };
102
103 template<typename R>
104 class /*LIBPBD_API*/ OptionalLastValue
105 {
106 public:
107         typedef boost::optional<R> result_type;
108
109         template <typename Iter>
110         result_type operator() (Iter first, Iter last) const {
111                 result_type r;
112                 while (first != last) {
113                         r = *first;
114                         ++first;
115                 }
116
117                 return r;
118         }
119 };
120
121 typedef boost::shared_ptr<Connection> UnscopedConnection;
122
123 class LIBPBD_API ScopedConnection
124 {
125 public:
126         ScopedConnection () {}
127         ScopedConnection (UnscopedConnection c) : _c (c) {}
128         ~ScopedConnection () {
129                 disconnect ();
130         }
131
132         void disconnect ()
133         {
134                 if (_c) {
135                         _c->disconnect ();
136                 }
137         }
138
139         ScopedConnection& operator= (UnscopedConnection const & o)
140         {
141                 if (_c == o) {
142                         return *this;
143                 }
144
145                 disconnect ();
146                 _c = o;
147                 return *this;
148         }
149
150 private:
151         UnscopedConnection _c;
152 };
153
154 class LIBPBD_API ScopedConnectionList  : public boost::noncopyable
155 {
156   public:
157         ScopedConnectionList();
158         virtual ~ScopedConnectionList ();
159
160         void add_connection (const UnscopedConnection& c);
161         void drop_connections ();
162
163   private:
164         /* this class is not copyable */
165         ScopedConnectionList(const ScopedConnectionList&);
166
167         /* Even though our signals code is thread-safe, this additional list of
168            scoped connections needs to be protected in 2 cases:
169
170            (1) (unlikely) we make a connection involving a callback on the
171                same object from 2 threads. (wouldn't that just be appalling
172                programming style?)
173
174            (2) where we are dropping connections in one thread and adding
175                one from another.
176          */
177
178         Glib::Threads::Mutex _lock;
179
180         typedef std::list<ScopedConnection*> ConnectionList;
181         ConnectionList _list;
182 };
183
184 #include "pbd/signals_generated.h"
185
186 } /* namespace */
187
188 #endif /* __pbd_signals_h__ */