diff options
Diffstat (limited to 'libs')
24 files changed, 344 insertions, 80 deletions
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 |