summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/strip_silence_dialog.cc5
-rw-r--r--libs/ardour/ardour/control_protocol_manager.h1
-rw-r--r--libs/ardour/ardour/midi_ui.h1
-rw-r--r--libs/ardour/audioengine.cc3
-rw-r--r--libs/ardour/control_protocol_manager.cc13
-rw-r--r--libs/ardour/globals.cc19
-rw-r--r--libs/ardour/midi_ui.cc13
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc4
-rw-r--r--libs/pbd/event_loop.cc106
-rw-r--r--libs/pbd/pbd/abstract_ui.cc79
-rw-r--r--libs/pbd/pbd/abstract_ui.h12
-rw-r--r--libs/pbd/pbd/event_loop.h33
-rw-r--r--libs/pbd/pbd/pthread_utils.h4
-rw-r--r--libs/pbd/pthread_utils.cc15
-rw-r--r--libs/surfaces/control_protocol/control_protocol/control_protocol.h28
-rw-r--r--libs/surfaces/faderport/faderport.cc19
-rw-r--r--libs/surfaces/faderport/faderport.h3
-rw-r--r--libs/surfaces/faderport/faderport_interface.cc9
-rw-r--r--libs/surfaces/mackie/interface.cc10
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc19
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h1
-rw-r--r--libs/surfaces/osc/interface.cc9
-rw-r--r--libs/surfaces/osc/osc.cc19
-rw-r--r--libs/surfaces/osc/osc.h2
-rw-r--r--libs/surfaces/wiimote/wiimote.cc2
25 files changed, 348 insertions, 81 deletions
diff --git a/gtk2_ardour/strip_silence_dialog.cc b/gtk2_ardour/strip_silence_dialog.cc
index 71d25d648e..cd41950924 100644
--- a/gtk2_ardour/strip_silence_dialog.cc
+++ b/gtk2_ardour/strip_silence_dialog.cc
@@ -237,7 +237,10 @@ StripSilenceDialog::_detection_thread_work (void* arg)
void *
StripSilenceDialog::detection_thread_work ()
{
- ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32);
+ /* Do not register with all UIs, but do register with the GUI,
+ because we will need to queue some GUI (only) requests
+ */
+ ARDOUR_UI::instance()->register_thread (pthread_self(), "silence", 32);
/* Hold this lock when we are doing work */
_lock.lock ();
diff --git a/libs/ardour/ardour/control_protocol_manager.h b/libs/ardour/ardour/control_protocol_manager.h
index 0c14d2a049..dbbb0c3891 100644
--- a/libs/ardour/ardour/control_protocol_manager.h
+++ b/libs/ardour/ardour/control_protocol_manager.h
@@ -65,6 +65,7 @@ class LIBARDOUR_API ControlProtocolManager : public PBD::Stateful, public ARDOUR
void load_mandatory_protocols ();
void midi_connectivity_established ();
void drop_protocols ();
+ void register_request_buffer_factories ();
int activate (ControlProtocolInfo&);
int deactivate (ControlProtocolInfo&);
diff --git a/libs/ardour/ardour/midi_ui.h b/libs/ardour/ardour/midi_ui.h
index 7f57f22e24..2f0f7d3a45 100644
--- a/libs/ardour/ardour/midi_ui.h
+++ b/libs/ardour/ardour/midi_ui.h
@@ -51,6 +51,7 @@ class LIBARDOUR_API MidiControlUI : public AbstractUI<MidiUIRequest>
~MidiControlUI ();
static MidiControlUI* instance() { return _instance; }
+ static void* request_factory (uint32_t num_requests);
void change_midi_ports ();
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 3452d1d14c..9c8407e8d7 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -1226,8 +1226,7 @@ AudioEngine::thread_init_callback (void* arg)
SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
- PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
- PBD::notify_gui_about_thread_creation ("midiUI", pthread_self(), X_("AudioEngine"), 128);
+ PBD::notify_event_loops_about_thread_creation (pthread_self(), X_("AudioEngine"), 4096);
AsyncMIDIPort::set_process_thread (pthread_self());
diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc
index 4e2cb7d9f7..6583869fed 100644
--- a/libs/ardour/control_protocol_manager.cc
+++ b/libs/ardour/control_protocol_manager.cc
@@ -22,6 +22,7 @@
#include <glibmm/fileutils.h>
#include "pbd/compose.h"
+#include "pbd/event_loop.h"
#include "pbd/file_utils.h"
#include "pbd/error.h"
@@ -487,3 +488,15 @@ ControlProtocolManager::midi_connectivity_established ()
(*p)->midi_connectivity_established ();
}
}
+
+void
+ControlProtocolManager::register_request_buffer_factories ()
+{
+ Glib::Threads::Mutex::Lock lm (protocols_lock);
+
+ for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
+ if ((*i)->descriptor->request_buffer_factory) {
+ EventLoop::register_request_buffer_factory ((*i)->descriptor->name, (*i)->descriptor->request_buffer_factory);
+ }
+ }
+}
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index b2ad67d053..9f4a1399b3 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -97,6 +97,7 @@
#include "ardour/event_type_map.h"
#include "ardour/filesystem_paths.h"
#include "ardour/midi_region.h"
+#include "ardour/midi_ui.h"
#include "ardour/midiport_manager.h"
#include "ardour/mix.h"
#include "ardour/operations.h"
@@ -513,6 +514,22 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
#endif
(void) EventTypeMap::instance();
+ ControlProtocolManager::instance().discover_control_protocols ();
+
+ /* for each control protocol, check for a request buffer factory method
+ and if it exists, store it in the EventLoop list of such
+ methods. This allows the relevant threads to register themselves
+ with EventLoops so that signal emission can be RT-safe.
+ */
+
+ ControlProtocolManager::instance().register_request_buffer_factories ();
+ /* it would be nice if this could auto-register itself in the
+ constructor, since MidiControlUI is a singleton, but it can't be
+ created until after the engine is running. Therefore we have to
+ explicitly register it here.
+ */
+ EventLoop::register_request_buffer_factory (X_("midiUI"), MidiControlUI::request_factory);
+
ProcessThread::init ();
/* the + 4 is a bit of a handwave. i don't actually know
how many more per-thread buffer sets we need above
@@ -553,8 +570,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
void
ARDOUR::init_post_engine ()
{
- ControlProtocolManager::instance().discover_control_protocols ();
-
XMLNode* node;
if ((node = Config->control_protocol_state()) != 0) {
ControlProtocolManager::instance().set_state (*node, Stateful::loading_state_version);
diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc
index 96304fa051..1d2fe7c7e1 100644
--- a/libs/ardour/midi_ui.cc
+++ b/libs/ardour/midi_ui.cc
@@ -60,6 +60,17 @@ MidiControlUI::~MidiControlUI ()
_instance = 0;
}
+void*
+MidiControlUI::request_factory (uint32_t num_requests)
+{
+ /* AbstractUI<T>::request_buffer_factory() is a template method only
+ instantiated in this source module. To provide something visible for
+ use when registering the factory, we have this static method that is
+ template-free.
+ */
+ return request_buffer_factory (num_requests);
+}
+
void
MidiControlUI::do_request (MidiUIRequest* req)
{
@@ -131,7 +142,7 @@ MidiControlUI::thread_init ()
pthread_set_name (X_("midiUI"));
- PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("midiUI"), 2048);
+ PBD::notify_event_loops_about_thread_creation (pthread_self(), X_("midiUI"), 2048);
SessionEvent::create_per_thread_pool (X_("midiUI"), 128);
memset (&rtparam, 0, sizeof (rtparam));
diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc
index ca4d6681dc..538bf8d63f 100644
--- a/libs/gtkmm2ext/gtk_ui.cc
+++ b/libs/gtkmm2ext/gtk_ui.cc
@@ -98,6 +98,10 @@ UI::UI (string namestr, int *argc, char ***argv)
set_event_loop_for_thread (this);
+ /* we will be receiving requests */
+
+ EventLoop::register_request_buffer_factory ("gui", request_buffer_factory);
+
/* attach our request source to the default main context */
attach_request_source ();
diff --git a/libs/pbd/event_loop.cc b/libs/pbd/event_loop.cc
index 95b43d9038..671e26bedc 100644
--- a/libs/pbd/event_loop.cc
+++ b/libs/pbd/event_loop.cc
@@ -17,9 +17,13 @@
*/
+#include "pbd/compose.h"
#include "pbd/event_loop.h"
+#include "pbd/error.h"
#include "pbd/stacktrace.h"
+#include "i18n.h"
+
using namespace PBD;
using namespace std;
@@ -27,13 +31,18 @@ static void do_not_delete_the_loop_pointer (void*) { }
Glib::Threads::Private<EventLoop> EventLoop::thread_event_loop (do_not_delete_the_loop_pointer);
+Glib::Threads::RWLock EventLoop::thread_buffer_requests_lock;
+EventLoop::ThreadRequestBufferList EventLoop::thread_buffer_requests;
+EventLoop::RequestBufferSuppliers EventLoop::request_buffer_suppliers;
+
EventLoop::EventLoop (string const& name)
: _name (name)
{
}
EventLoop*
-EventLoop::get_event_loop_for_thread() {
+EventLoop::get_event_loop_for_thread()
+{
return thread_event_loop.get ();
}
@@ -84,3 +93,98 @@ EventLoop::invalidate_request (void* data)
return 0;
}
+vector<EventLoop::ThreadBufferMapping>
+EventLoop::get_request_buffers_for_target_thread (const std::string& target_thread)
+{
+ vector<ThreadBufferMapping> ret;
+ Glib::Threads::RWLock::WriterLock lm (thread_buffer_requests_lock);
+
+ for (ThreadRequestBufferList::const_iterator x = thread_buffer_requests.begin();
+ x != thread_buffer_requests.end(); ++x) {
+
+ if (x->second.target_thread_name == target_thread) {
+ ret.push_back (x->second);
+ }
+ }
+
+ return ret;
+}
+
+void
+EventLoop::register_request_buffer_factory (const string& target_thread_name,
+ void* (*factory)(uint32_t))
+{
+
+ RequestBufferSupplier trs;
+ trs.name = target_thread_name;
+ trs.factory = factory;
+
+ {
+ Glib::Threads::RWLock::WriterLock lm (thread_buffer_requests_lock);
+ request_buffer_suppliers.push_back (trs);
+ }
+}
+
+void
+EventLoop::pre_register (const string& emitting_thread_name, uint32_t num_requests)
+{
+ /* Threads that need to emit signals "towards" other threads, but with
+ RT safe behavior may be created before the receiving threads
+ exist. This makes it impossible for them to use the
+ ThreadCreatedWithRequestSize signal to notify receiving threads of
+ their existence.
+
+ This function creates a request buffer for them to use with
+ the (not yet) created threads, and stores it where the receiving
+ thread can find it later.
+ */
+
+ ThreadBufferMapping mapping;
+ Glib::Threads::RWLock::ReaderLock lm (thread_buffer_requests_lock);
+
+ for (RequestBufferSuppliers::iterator trs = request_buffer_suppliers.begin(); trs != request_buffer_suppliers.end(); ++trs) {
+
+ if (!trs->factory) {
+ /* no factory - no request buffer required or expected */
+ continue;
+ }
+
+ if (emitting_thread_name == trs->name) {
+ /* no need to register an emitter with itself */
+ continue;
+ }
+
+ mapping.emitting_thread = pthread_self();
+ mapping.target_thread_name = trs->name;
+
+ /* Allocate a suitably sized request buffer. This will set the
+ * thread-local variable that holds a pointer to this request
+ * buffer.
+ */
+ mapping.request_buffer = trs->factory (num_requests);
+
+ /* now store it where the receiving thread (trs->name) can find
+ it if and when it is created. (Discovery happens in the
+ AbstractUI constructor. Note that if
+ */
+
+ /* make a key composed of the emitter and receiver thread names */
+
+ string key = emitting_thread_name;
+ key += '/';
+ key += mapping.target_thread_name;
+
+ /* if the emitting thread was killed and recreated (with the
+ * same name), this will replace the entry in
+ * thread_buffer_requests. The old entry will be lazily deleted
+ * when the target thread finds the request buffer and realizes
+ * that it is dead.
+ *
+ * If the request buffer is replaced before the target thread
+ * ever finds the dead version, we will leak the old request
+ * buffer.
+ */
+
+ thread_buffer_requests[key] = mapping;
+ }
+}
diff --git a/libs/pbd/pbd/abstract_ui.cc b/libs/pbd/pbd/abstract_ui.cc
index d3d3c2e8b1..1514455b42 100644
--- a/libs/pbd/pbd/abstract_ui.cc
+++ b/libs/pbd/pbd/abstract_ui.cc
@@ -14,7 +14,6 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
*/
#include <unistd.h>
@@ -65,17 +64,28 @@ template <typename RequestObject>
AbstractUI<RequestObject>::AbstractUI (const string& name)
: BaseUI (name)
{
- void (AbstractUI<RequestObject>::*pmf)(string,pthread_t,string,uint32_t) = &AbstractUI<RequestObject>::register_thread;
+ void (AbstractUI<RequestObject>::*pmf)(pthread_t,string,uint32_t) = &AbstractUI<RequestObject>::register_thread;
/* better to make this connect a handler that runs in the UI event loop but the syntax seems hard, and
register_thread() is thread safe anyway.
*/
- PBD::ThreadCreatedWithRequestSize.connect_same_thread (new_thread_connection, boost::bind (pmf, this, _1, _2, _3, _4));
+ PBD::ThreadCreatedWithRequestSize.connect_same_thread (new_thread_connection, boost::bind (pmf, this, _1, _2, _3));
+
+ /* find pre-registerer threads */
+
+ vector<EventLoop::ThreadBufferMapping> tbm = EventLoop::get_request_buffers_for_target_thread (event_loop_name());
+
+ {
+ Glib::Threads::Mutex::Lock lm (request_buffer_map_lock);
+ for (vector<EventLoop::ThreadBufferMapping>::iterator t = tbm.begin(); t != tbm.end(); ++t) {
+ request_buffers[t->emitting_thread] = static_cast<RequestBuffer*> (t->request_buffer);
+ }
+ }
}
template <typename RequestObject> void
-AbstractUI<RequestObject>::register_thread (string target_gui, pthread_t thread_id, string thread_name, uint32_t num_requests)
+AbstractUI<RequestObject>::register_thread (pthread_t thread_id, string thread_name, uint32_t num_requests)
{
/* the calling thread wants to register with the thread that runs this
* UI's event loop, so that it will have its own per-thread queue of
@@ -83,36 +93,39 @@ AbstractUI<RequestObject>::register_thread (string target_gui, pthread_t thread_
* do so in a realtime-safe manner (no locks).
*/
- DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("in %1 (thread name %4), %2 (%5) wants to register with %3\n", event_loop_name(), thread_name, target_gui, pthread_name(), DEBUG_THREAD_SELF));
-
- if (target_gui != event_loop_name()) {
- /* this UI is not the UI that the calling thread is trying to
- register with
- */
- DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1 : not the registration target\n", event_loop_name()));
- return;
- }
+ DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("in %1 (thread name %4), %2 (%5) wants to register with UIs\n", event_loop_name(), thread_name, pthread_name(), DEBUG_THREAD_SELF));
/* the per_thread_request_buffer is a thread-private variable.
See pthreads documentation for more on these, but the key
thing is that it is a variable that as unique value for
- each thread, guaranteed.
+ each thread, guaranteed. Note that the thread in question
+ is the caller of this function, which is assumed to be the
+ thread from which signals will be emitted that this UI's
+ event loop will catch.
*/
RequestBuffer* b = per_thread_request_buffer.get();
- if (b) {
- /* thread already registered with this UI
- */
- DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1 : %2 is already registered\n", event_loop_name(), thread_name));
- return;
- }
+ if (!b) {
- /* create a new request queue/ringbuffer */
+ /* create a new request queue/ringbuffer */
- DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("create new request buffer for %1 in %2\n", thread_name, event_loop_name()));
+ DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("create new request buffer for %1 in %2\n", thread_name, event_loop_name()));
- b = new RequestBuffer (num_requests, *this);
+ b = new RequestBuffer (num_requests);
+ /* set this thread's per_thread_request_buffer to this new
+ queue/ringbuffer. remember that only this thread will
+ get this queue when it calls per_thread_request_buffer.get()
+
+ the second argument is a function that will be called
+ when the thread exits, and ensures that the buffer is marked
+ dead. it will then be deleted during a call to handle_ui_requests()
+ */
+
+ per_thread_request_buffer.set (b);
+ } else {
+ DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1 : %2 is already registered\n", event_loop_name(), thread_name));
+ }
{
/* add the new request queue (ringbuffer) to our map
@@ -125,16 +138,6 @@ AbstractUI<RequestObject>::register_thread (string target_gui, pthread_t thread_
request_buffers[thread_id] = b;
}
- /* set this thread's per_thread_request_buffer to this new
- queue/ringbuffer. remember that only this thread will
- get this queue when it calls per_thread_request_buffer.get()
-
- the second argument is a function that will be called
- when the thread exits, and ensures that the buffer is marked
- dead. it will then be deleted during a call to handle_ui_requests()
- */
-
- per_thread_request_buffer.set (b);
}
template <typename RequestObject> RequestObject*
@@ -229,6 +232,7 @@ AbstractUI<RequestObject>::handle_ui_requests ()
if ((*i).second->dead) {
DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1/%2 deleting dead per-thread request buffer for %3 @ %4\n",
event_loop_name(), pthread_name(), i->second));
+ cerr << event_loop_name() << " noticed that a buffer was dead\n";
delete (*i).second;
RequestBufferMapIterator tmp = i;
++tmp;
@@ -357,6 +361,7 @@ AbstractUI<RequestObject>::send_request (RequestObject *req)
single-reader/single-writer semantics
*/
DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1/%2 send heap request type %3\n", event_loop_name(), pthread_name(), req->type));
+ cerr << "Send request to " << event_loop_name() << " via LIST from " << pthread_name() << endl;
Glib::Threads::Mutex::Lock lm (request_list_lock);
request_list.push_back (req);
}
@@ -407,3 +412,11 @@ AbstractUI<RequestObject>::call_slot (InvalidationRecord* invalidation, const bo
send_request (req);
}
+
+template<typename RequestObject> void*
+AbstractUI<RequestObject>::request_buffer_factory (uint32_t num_requests)
+{
+ RequestBuffer* mcr = new RequestBuffer (num_requests);
+ per_thread_request_buffer.set (mcr);
+ return mcr;
+}
diff --git a/libs/pbd/pbd/abstract_ui.h b/libs/pbd/pbd/abstract_ui.h
index 5491210db7..78a337fc40 100644
--- a/libs/pbd/pbd/abstract_ui.h
+++ b/libs/pbd/pbd/abstract_ui.h
@@ -58,20 +58,20 @@ class ABSTRACT_UI_API AbstractUI : public BaseUI
AbstractUI (const std::string& name);
virtual ~AbstractUI() {}
- void register_thread (std::string, pthread_t, std::string, uint32_t num_requests);
+ void register_thread (pthread_t, std::string, uint32_t num_requests);
void call_slot (EventLoop::InvalidationRecord*, const boost::function<void()>&);
Glib::Threads::Mutex& slot_invalidation_mutex() { return request_buffer_map_lock; }
Glib::Threads::Mutex request_buffer_map_lock;
+ static void* request_buffer_factory (uint32_t num_requests);
+
protected:
struct RequestBuffer : public PBD::RingBufferNPT<RequestObject> {
bool dead;
- AbstractUI<RequestObject>& ui;
- RequestBuffer (uint32_t size, AbstractUI<RequestObject>& uir)
+ RequestBuffer (uint32_t size)
: PBD::RingBufferNPT<RequestObject> (size)
- , dead (false)
- , ui (uir) {}
+ , dead (false) {}
};
typedef typename RequestBuffer::rw_vector RequestBufferVector;
@@ -105,5 +105,3 @@ class ABSTRACT_UI_API AbstractUI : public BaseUI
};
#endif /* __pbd_abstract_ui_h__ */
-
-
diff --git a/libs/pbd/pbd/event_loop.h b/libs/pbd/pbd/event_loop.h
index 3ea6388f3f..90d72ef47c 100644
--- a/libs/pbd/pbd/event_loop.h
+++ b/libs/pbd/pbd/event_loop.h
@@ -21,6 +21,8 @@
#define __pbd_event_loop_h__
#include <string>
+#include <vector>
+#include <map>
#include <boost/function.hpp>
#include <boost/bind.hpp> /* we don't need this here, but anything calling call_slot() probably will, so this is convenient */
#include <glibmm/threads.h>
@@ -79,9 +81,40 @@ class LIBPBD_API EventLoop
static EventLoop* get_event_loop_for_thread();
static void set_event_loop_for_thread (EventLoop* ui);
+ struct ThreadBufferMapping {
+ pthread_t emitting_thread;
+ std::string target_thread_name;
+ void* request_buffer;
+ };
+
+ static std::vector<ThreadBufferMapping> get_request_buffers_for_target_thread (const std::string&);
+
+ static void register_request_buffer_factory (const std::string& target_thread_name, void* (*factory) (uint32_t));
+ static void pre_register (const std::string& emitting_thread_name, uint32_t num_requests);
+
private:
static Glib::Threads::Private<EventLoop> thread_event_loop;
std::string _name;
+
+ typedef std::map<std::string,ThreadBufferMapping> ThreadRequestBufferList;
+ static ThreadRequestBufferList thread_buffer_requests;
+ static Glib::Threads::RWLock thread_buffer_requests_lock;
+
+ struct RequestBufferSupplier {
+
+ /* @param name : name of object/entity that will/may accept
+ requests from other threads, via a request buffer.
+ */
+ std::string name;
+
+ /* @param factory : a function that can be called (with an
+ argument specifying the @param number_of_requests) to create and
+ return a request buffer for communicating with @param name)
+ */
+ void* (*factory)(uint32_t nunber_of_requests);
+ };
+ typedef std::vector<RequestBufferSupplier> RequestBufferSuppliers;
+ static RequestBufferSuppliers request_buffer_suppliers;
};
}
diff --git a/libs/pbd/pbd/pthread_utils.h b/libs/pbd/pbd/pthread_utils.h
index a5173ad24d..8f70fdac5b 100644
--- a/libs/pbd/pbd/pthread_utils.h
+++ b/libs/pbd/pbd/pthread_utils.h
@@ -55,8 +55,8 @@ LIBPBD_API const char* pthread_name ();
LIBPBD_API void pthread_set_name (const char* name);
namespace PBD {
- LIBPBD_API extern void notify_gui_about_thread_creation (std::string, pthread_t, std::string, int requests = 256);
- LIBPBD_API extern PBD::Signal4<void,std::string,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
+ LIBPBD_API extern void notify_event_loops_about_thread_creation (pthread_t, const std::string&, int requests = 256);
+ LIBPBD_API extern PBD::Signal3<void,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
}
#endif /* __pbd_pthread_utils__ */
diff --git a/libs/pbd/pthread_utils.cc b/libs/pbd/pthread_utils.cc
index 1abe6a95fb..7cd25e42b8 100644
--- a/libs/pbd/pthread_utils.cc
+++ b/libs/pbd/pthread_utils.cc
@@ -44,7 +44,7 @@ static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
static Glib::Threads::Private<char> thread_name (free);
namespace PBD {
- PBD::Signal4<void,std::string, pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
+ PBD::Signal3<void,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
}
using namespace PBD;
@@ -58,10 +58,18 @@ static int thread_creator (pthread_t* thread_id, const pthread_attr_t* attr, voi
#endif
}
+
void
-PBD::notify_gui_about_thread_creation (std::string target_gui, pthread_t thread, std::string str, int request_count)
+PBD::notify_event_loops_about_thread_creation (pthread_t thread, const std::string& emitting_thread_name, int request_count)
{
- ThreadCreatedWithRequestSize (target_gui, thread, str, request_count);
+ /* notify threads that may exist in the future (they may also exist
+ * already, in which case they will catch the
+ * ThreadCreatedWithRequestSize signal)
+ */
+ EventLoop::pre_register (emitting_thread_name, request_count);
+
+ /* notify all existing threads */
+ ThreadCreatedWithRequestSize (thread, emitting_thread_name, request_count);
}
struct ThreadStartWithName {
@@ -199,4 +207,3 @@ pthread_cancel_one (pthread_t thread)
pthread_cancel (thread);
pthread_mutex_unlock (&thread_map_lock);
}
-
diff --git a/libs/surfaces/control_protocol/control_protocol/control_protocol.h b/libs/surfaces/control_protocol/control_protocol/control_protocol.h
index 8edb3f39a7..71e875419a 100644
--- a/libs/surfaces/control_protocol/control_protocol/control_protocol.h
+++ b/libs/surfaces/control_protocol/control_protocol/control_protocol.h
@@ -154,16 +154,24 @@ class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::Scope
extern "C" {
class ControlProtocolDescriptor {
public:
- const char* name; /* descriptive */
- const char* id; /* unique and version-specific */
- void* ptr; /* protocol can store a value here */
- void* module; /* not for public access */
- int mandatory; /* if non-zero, always load and do not make optional */
- bool supports_feedback; /* if true, protocol has toggleable feedback mechanism */
- bool (*probe)(ControlProtocolDescriptor*);
- ControlProtocol* (*initialize)(ControlProtocolDescriptor*,Session*);
- void (*destroy)(ControlProtocolDescriptor*,ControlProtocol*);
-
+ const char* name; /* descriptive */
+ const char* id; /* unique and version-specific */
+ void* ptr; /* protocol can store a value here */
+ void* module; /* not for public access */
+ int mandatory; /* if non-zero, always load and do not make optional */
+ bool supports_feedback; /* if true, protocol has toggleable feedback mechanism */
+ bool (*probe)(ControlProtocolDescriptor*);
+ ControlProtocol* (*initialize)(ControlProtocolDescriptor*,Session*);
+ void (*destroy)(ControlProtocolDescriptor*,ControlProtocol*);
+ /* this is required if the control protocol connects to signals
+ from libardour. they all do. It should allocate a
+ type-specific request buffer for the calling thread, and
+ store it in a thread-local location that will be used to
+ find it when sending the event loop a message
+ (e.g. call_slot()). It should also return the allocated
+ buffer as a void*.
+ */
+ void* (*request_buffer_factory)(uint32_t);
};
}
diff --git a/libs/surfaces/faderport/faderport.cc b/libs/surfaces/faderport/faderport.cc
index 135943d34f..f10f70dce5 100644
--- a/libs/surfaces/faderport/faderport.cc
+++ b/libs/surfaces/faderport/faderport.cc
@@ -66,7 +66,7 @@ using namespace std;
FaderPort::FaderPort (Session& s)
: ControlProtocol (s, _("Faderport"))
- , AbstractUI<FaderPortRequest> ("faderport")
+ , AbstractUI<FaderPortRequest> (name())
, gui (0)
, connection_state (ConnectionState (0))
, _device_active (false)
@@ -210,6 +210,17 @@ FaderPort::~FaderPort ()
tear_down_gui ();
}
+void*
+FaderPort::request_factory (uint32_t num_requests)
+{
+ /* AbstractUI<T>::request_buffer_factory() is a template method only
+ instantiated in this source module. To provide something visible for
+ use in the interface/descriptor, we have this static method that is
+ template-free.
+ */
+ return request_buffer_factory (num_requests);
+}
+
void
FaderPort::start_midi_handling ()
{
@@ -267,10 +278,10 @@ FaderPort::thread_init ()
{
struct sched_param rtparam;
- pthread_set_name (X_("FaderPort"));
+ pthread_set_name (event_loop_name().c_str());
- PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("FaderPort"), 2048);
- ARDOUR::SessionEvent::create_per_thread_pool (X_("FaderPort"), 128);
+ PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
+ ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
memset (&rtparam, 0, sizeof (rtparam));
rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
diff --git a/libs/surfaces/faderport/faderport.h b/libs/surfaces/faderport/faderport.h
index 6643e22369..025cf09e00 100644
--- a/libs/surfaces/faderport/faderport.h
+++ b/libs/surfaces/faderport/faderport.h
@@ -85,6 +85,7 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
there's no way to know if the device exists or not.
*/
static bool probe() { return true; }
+ static void* request_factory (uint32_t);
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
@@ -160,7 +161,7 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
std::string get_action (ButtonID, bool on_press, FaderPort::ButtonState = ButtonState (0));
std::list<boost::shared_ptr<ARDOUR::Bundle> > bundles ();
-
+
private:
boost::shared_ptr<ARDOUR::Route> _current_route;
boost::weak_ptr<ARDOUR::Route> pre_master_route;
diff --git a/libs/surfaces/faderport/faderport_interface.cc b/libs/surfaces/faderport/faderport_interface.cc
index dcfebff190..e7ea5af396 100644
--- a/libs/surfaces/faderport/faderport_interface.cc
+++ b/libs/surfaces/faderport/faderport_interface.cc
@@ -56,6 +56,12 @@ probe_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/)
return FaderPort::probe ();
}
+static void*
+faderport_request_buffer_factory (uint32_t num_requests)
+{
+ return FaderPort::request_factory (num_requests);
+}
+
static ControlProtocolDescriptor faderport_midi_descriptor = {
/*name : */ "Faderport",
/*id : */ "uri://ardour.org/surfaces/faderport:0",
@@ -65,7 +71,8 @@ static ControlProtocolDescriptor faderport_midi_descriptor = {
/*supports_feedback : */ true,
/*probe : */ probe_faderport_midi_protocol,
/*initialize : */ new_faderport_midi_protocol,
- /*destroy : */ delete_faderport_midi_protocol
+ /*destroy : */ delete_faderport_midi_protocol,
+ /*request_buffer_factory */ faderport_request_buffer_factory
};
extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &faderport_midi_descriptor; }
diff --git a/libs/surfaces/mackie/interface.cc b/libs/surfaces/mackie/interface.cc
index 1a9760bcbe..3b04770660 100644
--- a/libs/surfaces/mackie/interface.cc
+++ b/libs/surfaces/mackie/interface.cc
@@ -74,6 +74,12 @@ probe_mackie_protocol (ControlProtocolDescriptor*)
return MackieControlProtocol::probe();
}
+static void*
+mackie_request_buffer_factory (uint32_t num_requests)
+{
+ return MackieControlProtocol::request_factory (num_requests);
+}
+
// Field names commented out by JE - 06-01-2010
static ControlProtocolDescriptor mackie_descriptor = {
/*name : */ "Mackie",
@@ -88,8 +94,8 @@ static ControlProtocolDescriptor mackie_descriptor = {
/*supports_feedback : */ false,
/*probe : */ probe_mackie_protocol,
/*initialize : */ new_mackie_protocol,
- /*destroy : */ delete_mackie_protocol
+ /*destroy : */ delete_mackie_protocol,
+ /*request_buffer_factory */ mackie_request_buffer_factory
};
-
extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &mackie_descriptor; }
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index dfd3fe6334..ea5e43d2ba 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -105,7 +105,7 @@ bool MackieControlProtocol::probe()
MackieControlProtocol::MackieControlProtocol (Session& session)
: ControlProtocol (session, X_("Mackie"))
- , AbstractUI<MackieControlUIRequest> ("mackie")
+ , AbstractUI<MackieControlUIRequest> (name())
, _current_initial_bank (0)
, _frame_last (0)
, _timecode_type (ARDOUR::AnyTime::BBT)
@@ -183,10 +183,10 @@ MackieControlProtocol::thread_init ()
{
struct sched_param rtparam;
- pthread_set_name (X_("MackieControl"));
+ pthread_set_name (event_loop_name().c_str());
- PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("MackieControl"), 2048);
- ARDOUR::SessionEvent::create_per_thread_pool (X_("MackieControl"), 128);
+ PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
+ ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
memset (&rtparam, 0, sizeof (rtparam));
rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
@@ -2251,3 +2251,14 @@ MackieControlProtocol::global_index (Strip& strip)
return global;
}
+
+void*
+MackieControlProtocol::request_factory (uint32_t num_requests)
+{
+ /* AbstractUI<T>::request_buffer_factory() is a template method only
+ instantiated in this source module. To provide something visible for
+ use in the interface/descriptor, we have this static method that is
+ template-free.
+ */
+ return request_buffer_factory (num_requests);
+}
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
index a1cee8ec7f..802d5a6235 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.h
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -178,6 +178,7 @@ class MackieControlProtocol
*/
static bool probe();
+ static void* request_factory (uint32_t);
mutable Glib::Threads::Mutex surfaces_lock;
typedef std::list<boost::shared_ptr<Mackie::Surface> > Surfaces;
diff --git a/libs/surfaces/osc/interface.cc b/libs/surfaces/osc/interface.cc
index d26a31788e..35b313945d 100644
--- a/libs/surfaces/osc/interface.cc
+++ b/libs/surfaces/osc/interface.cc
@@ -46,6 +46,12 @@ probe_osc_protocol (ControlProtocolDescriptor* /*descriptor*/)
return true; // we can always do OSC
}
+static void*
+osc_request_buffer_factory (uint32_t num_requests)
+{
+ return OSC::request_factory (num_requests);
+}
+
static ControlProtocolDescriptor osc_descriptor = {
/*name : */ "Open Sound Control (OSC)",
/*id : */ "uri://ardour.org/surfaces/osc:0",
@@ -55,7 +61,8 @@ static ControlProtocolDescriptor osc_descriptor = {
/*supports_feedback : */ true,
/*probe : */ probe_osc_protocol,
/*initialize : */ new_osc_protocol,
- /*destroy : */ delete_osc_protocol
+ /*destroy : */ delete_osc_protocol,
+ /*request_buffer_factory */ osc_request_buffer_factory
};
extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &osc_descriptor; }
diff --git a/libs/surfaces/osc/osc.cc b/libs/surfaces/osc/osc.cc
index 13261feffa..49c8bcc57c 100644
--- a/libs/surfaces/osc/osc.cc
+++ b/libs/surfaces/osc/osc.cc
@@ -73,7 +73,7 @@ static void error_callback(int, const char *, const char *)
OSC::OSC (Session& s, uint32_t port)
: ControlProtocol (s, X_("Open Sound Control (OSC)"))
- , AbstractUI<OSCUIRequest> ("osc")
+ , AbstractUI<OSCUIRequest> (name())
, local_server (0)
, remote_server (0)
, _port(port)
@@ -96,6 +96,17 @@ OSC::~OSC()
_instance = 0;
}
+void*
+OSC::request_factory (uint32_t num_requests)
+{
+ /* AbstractUI<T>::request_buffer_factory() is a template method only
+ instantiated in this source module. To provide something visible for
+ use in the interface/descriptor, we have this static method that is
+ template-free.
+ */
+ return request_buffer_factory (num_requests);
+}
+
void
OSC::do_request (OSCUIRequest* req)
{
@@ -226,7 +237,7 @@ OSC::start ()
void
OSC::thread_init ()
{
- pthread_set_name (X_("OSC"));
+ pthread_set_name (event_loop_name().c_str());
if (_osc_unix_server) {
Glib::RefPtr<IOSource> src = IOSource::create (lo_server_get_socket_fd (_osc_unix_server), IO_IN|IO_HUP|IO_ERR);
@@ -244,8 +255,8 @@ OSC::thread_init ()
g_source_ref (remote_server);
}
- PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("OSC"), 2048);
- SessionEvent::create_per_thread_pool (X_("OSC"), 128);
+ PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
+ SessionEvent::create_per_thread_pool (event_loop_name(), 128);
}
int
diff --git a/libs/surfaces/osc/osc.h b/libs/surfaces/osc/osc.h
index 7c24869a00..3718d25525 100644
--- a/libs/surfaces/osc/osc.h
+++ b/libs/surfaces/osc/osc.h
@@ -79,6 +79,8 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
int start ();
int stop ();
+ static void* request_factory (uint32_t);
+
protected:
void thread_init ();
void do_request (OSCUIRequest*);
diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
index aa36cdf300..db5fb55c2a 100644
--- a/libs/surfaces/wiimote/wiimote.cc
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -164,7 +164,7 @@ WiimoteControlProtocol::thread_init ()
pthread_set_name (X_("wiimote"));
// allow to make requests to the GUI and RT thread(s)
- PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self (), X_("wiimote"), 2048);
+ PBD::notify_event_loops_about_thread_creation (pthread_self (), X_("wiimote"), 2048);
BasicUI::register_thread ("wiimote");
// connect a Wiimote