libpbd: changes to pre-registration of signal emitting threads
There is no need to preallocate request buffers for these threads - the event loops that require them can allocate them when they discover and register the pre-registered threads. This also means that event loops do not need to register request buffer factories.
This commit is contained in:
parent
ba66381ab0
commit
b0586763ba
|
@ -72,7 +72,6 @@ class LIBARDOUR_API ControlProtocolManager : public PBD::Stateful, public ARDOUR
|
||||||
void load_mandatory_protocols ();
|
void load_mandatory_protocols ();
|
||||||
void midi_connectivity_established ();
|
void midi_connectivity_established ();
|
||||||
void drop_protocols ();
|
void drop_protocols ();
|
||||||
void register_request_buffer_factories ();
|
|
||||||
|
|
||||||
int activate (ControlProtocolInfo&);
|
int activate (ControlProtocolInfo&);
|
||||||
int deactivate (ControlProtocolInfo&);
|
int deactivate (ControlProtocolInfo&);
|
||||||
|
|
|
@ -577,24 +577,6 @@ ControlProtocolManager::midi_connectivity_established ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ControlProtocolManager::register_request_buffer_factories ()
|
|
||||||
{
|
|
||||||
Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
|
|
||||||
|
|
||||||
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
|
|
||||||
|
|
||||||
if ((*i)->descriptor == 0) {
|
|
||||||
warning << string_compose (_("Control protocol \"%1\" has no descriptor"), (*i)->name) << endmsg;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*i)->descriptor->request_buffer_factory) {
|
|
||||||
EventLoop::register_request_buffer_factory ((*i)->descriptor->name, (*i)->descriptor->request_buffer_factory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlProtocolManager::stripable_selection_changed (StripableNotificationListPtr sp)
|
ControlProtocolManager::stripable_selection_changed (StripableNotificationListPtr sp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -651,20 +651,6 @@ ARDOUR::init (bool try_optimization, const char* localedir, bool with_gui)
|
||||||
|
|
||||||
ControlProtocolManager::instance ().discover_control_protocols ();
|
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);
|
|
||||||
|
|
||||||
/* Every Process Graph thread (up to hardware_concurrency) keeps a buffer.
|
/* Every Process Graph thread (up to hardware_concurrency) keeps a buffer.
|
||||||
* The main engine callback uses one (but returns it after use
|
* The main engine callback uses one (but returns it after use
|
||||||
* each cycle). Session Export uses one, and the GUI requires
|
* each cycle). Session Export uses one, and the GUI requires
|
||||||
|
|
|
@ -106,10 +106,6 @@ UI::UI (string application_name, string thread_name, int *argc, char ***argv)
|
||||||
|
|
||||||
set_event_loop_for_thread (this);
|
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 our request source to the default main context */
|
||||||
|
|
||||||
attach_request_source ();
|
attach_request_source ();
|
||||||
|
|
|
@ -37,7 +37,7 @@ 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::Private<EventLoop> EventLoop::thread_event_loop (do_not_delete_the_loop_pointer);
|
||||||
|
|
||||||
Glib::Threads::RWLock EventLoop::thread_buffer_requests_lock;
|
Glib::Threads::Mutex EventLoop::thread_buffer_requests_lock;
|
||||||
EventLoop::ThreadRequestBufferList EventLoop::thread_buffer_requests;
|
EventLoop::ThreadRequestBufferList EventLoop::thread_buffer_requests;
|
||||||
EventLoop::RequestBufferSuppliers EventLoop::request_buffer_suppliers;
|
EventLoop::RequestBufferSuppliers EventLoop::request_buffer_suppliers;
|
||||||
|
|
||||||
|
@ -113,16 +113,13 @@ vector<EventLoop::ThreadBufferMapping>
|
||||||
EventLoop::get_request_buffers_for_target_thread (const std::string& target_thread)
|
EventLoop::get_request_buffers_for_target_thread (const std::string& target_thread)
|
||||||
{
|
{
|
||||||
vector<ThreadBufferMapping> ret;
|
vector<ThreadBufferMapping> ret;
|
||||||
Glib::Threads::RWLock::WriterLock lm (thread_buffer_requests_lock);
|
Glib::Threads::Mutex::Lock lm (thread_buffer_requests_lock);
|
||||||
|
|
||||||
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("%1 look for request buffers via %2\n", pthread_name(), target_thread));
|
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("%1 look for request buffers via %2\n", pthread_name(), target_thread));
|
||||||
|
|
||||||
for (ThreadRequestBufferList::const_iterator x = thread_buffer_requests.begin(); x != thread_buffer_requests.end(); ++x) {
|
for (auto const & tbr : thread_buffer_requests) {
|
||||||
|
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("for thread \"%1\", request buffer for %2 (%3) thread %4\n", target_thread, tbr.emitting_thread, tbr.num_requests));
|
||||||
if (x->second.target_thread_name == target_thread) {
|
ret.push_back (tbr);
|
||||||
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("for thread \"%1\", request buffer for %2/%3 thread %4\n", target_thread, x->first, x->second.emitting_thread));
|
|
||||||
ret.push_back (x->second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("for thread \"%1\", found %2 request buffers\n", target_thread, ret.size()));
|
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("for thread \"%1\", found %2 request buffers\n", target_thread, ret.size()));
|
||||||
|
@ -130,21 +127,6 @@ EventLoop::get_request_buffers_for_target_thread (const std::string& target_thre
|
||||||
return ret;
|
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);
|
|
||||||
}
|
|
||||||
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("event loop %1 registered a buffer factory for %2\n", pthread_name(), target_thread_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
EventLoop::pre_register (const string& emitting_thread_name, uint32_t num_requests)
|
EventLoop::pre_register (const string& emitting_thread_name, uint32_t num_requests)
|
||||||
{
|
{
|
||||||
|
@ -160,46 +142,19 @@ EventLoop::pre_register (const string& emitting_thread_name, uint32_t num_reques
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ThreadBufferMapping mapping;
|
ThreadBufferMapping mapping;
|
||||||
Glib::Threads::RWLock::WriterLock lm (thread_buffer_requests_lock);
|
Glib::Threads::Mutex::Lock 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.emitting_thread = pthread_self();
|
||||||
mapping.target_thread_name = trs->name;
|
mapping.num_requests = num_requests;
|
||||||
|
|
||||||
/* 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
|
/* now store it where the receiving thread (trs->name) can find
|
||||||
it if and when it is created. (Discovery happens in the
|
it if and when it is created. (Discovery happens in the
|
||||||
AbstractUI constructor. Note that if
|
AbstractUI constructor. Note that if
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const string key = string_compose ("%1/%2", emitting_thread_name, mapping.target_thread_name);
|
|
||||||
|
|
||||||
/* management of the thread_request_buffers map works as
|
/* management of the thread_request_buffers map works as
|
||||||
* follows:
|
* follows:
|
||||||
*
|
*
|
||||||
* when the factory method was called above, the pointer to the
|
|
||||||
* created buffer is set as a thread-local-storage (TLS) value
|
|
||||||
* for this (the emitting) thread.
|
|
||||||
*
|
|
||||||
* The TLS value is set up with a destructor that marks the
|
|
||||||
* request buffer as "dead" when the emitting thread exits.
|
|
||||||
*
|
|
||||||
* An entry will remain in the map after the thread exits.
|
* An entry will remain in the map after the thread exits.
|
||||||
*
|
*
|
||||||
* The receiving thread may (if it receives requests from other
|
* The receiving thread may (if it receives requests from other
|
||||||
|
@ -226,19 +181,17 @@ EventLoop::pre_register (const string& emitting_thread_name, uint32_t num_reques
|
||||||
* lifetime anyway.
|
* lifetime anyway.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
thread_buffer_requests[key] = mapping;
|
thread_buffer_requests.push_back (mapping);
|
||||||
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("pre-registered request buffer for \"%1\" to send to \"%2\", buffer @ %3 (key was %4)\n",
|
DEBUG_TRACE (PBD::DEBUG::EventLoop, string_compose ("pre-registered thread \"%1\"\n", emitting_thread_name));
|
||||||
emitting_thread_name, trs->name, mapping.request_buffer, key));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EventLoop::remove_request_buffer_from_map (void* ptr)
|
EventLoop::remove_request_buffer_from_map (pthread_t pth)
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (thread_buffer_requests_lock);
|
Glib::Threads::Mutex::Lock lm (thread_buffer_requests_lock);
|
||||||
|
|
||||||
for (ThreadRequestBufferList::iterator x = thread_buffer_requests.begin(); x != thread_buffer_requests.end(); ++x) {
|
for (ThreadRequestBufferList::iterator x = thread_buffer_requests.begin(); x != thread_buffer_requests.end(); ++x) {
|
||||||
if (x->second.request_buffer == ptr) {
|
if (x->emitting_thread == pth) {
|
||||||
thread_buffer_requests.erase (x);
|
thread_buffer_requests.erase (x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,9 +87,11 @@ AbstractUI<RequestObject>::AbstractUI (const string& name)
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock rbml (request_buffer_map_lock);
|
Glib::Threads::RWLock::WriterLock rbml (request_buffer_map_lock);
|
||||||
|
|
||||||
for (vector<EventLoop::ThreadBufferMapping>::iterator t = tbm.begin(); t != tbm.end(); ++t) {
|
for (auto const & t : tbm) {
|
||||||
request_buffers[t->emitting_thread] = static_cast<RequestBuffer*> (t->request_buffer);
|
request_buffers[t.emitting_thread] = new RequestBuffer (t.num_requests);
|
||||||
DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%6: %1/%2/%3 create pre-registered request buffer-A @ %4 for %5\n", event_loop_name(), pthread_name(), pthread_self(), t->request_buffer, t->emitting_thread, this));
|
DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%6: %1/%2/%3 create pre-registered request buffer-A @ %4 for %5\n",
|
||||||
|
event_loop_name(), pthread_name(), pthread_self(),
|
||||||
|
request_buffers[t.emitting_thread], t.emitting_thread, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,12 +99,6 @@ AbstractUI<RequestObject>::AbstractUI (const string& name)
|
||||||
template <typename RequestObject>
|
template <typename RequestObject>
|
||||||
AbstractUI<RequestObject>::~AbstractUI ()
|
AbstractUI<RequestObject>::~AbstractUI ()
|
||||||
{
|
{
|
||||||
for (RequestBufferMapIterator i = request_buffers.begin(); i != request_buffers.end(); ++i) {
|
|
||||||
if ((*i).second->dead) {
|
|
||||||
EventLoop::remove_request_buffer_from_map ((*i).second);
|
|
||||||
delete (*i).second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename RequestObject> void
|
template <typename RequestObject> void
|
||||||
|
@ -326,7 +322,7 @@ AbstractUI<RequestObject>::handle_ui_requests ()
|
||||||
RequestBufferMapIterator tmp = i;
|
RequestBufferMapIterator tmp = i;
|
||||||
++tmp;
|
++tmp;
|
||||||
/* remove it from the EventLoop static map of all request buffers */
|
/* remove it from the EventLoop static map of all request buffers */
|
||||||
EventLoop::remove_request_buffer_from_map ((*i).second);
|
EventLoop::remove_request_buffer_from_map (i->first);
|
||||||
/* delete it
|
/* delete it
|
||||||
*
|
*
|
||||||
* Deleting the ringbuffer destroys all RequestObjects
|
* Deleting the ringbuffer destroys all RequestObjects
|
||||||
|
|
|
@ -99,15 +99,13 @@ public:
|
||||||
|
|
||||||
struct ThreadBufferMapping {
|
struct ThreadBufferMapping {
|
||||||
pthread_t emitting_thread;
|
pthread_t emitting_thread;
|
||||||
std::string target_thread_name;
|
size_t num_requests;
|
||||||
void* request_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<ThreadBufferMapping> get_request_buffers_for_target_thread (const std::string&);
|
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);
|
static void pre_register (const std::string& emitting_thread_name, uint32_t num_requests);
|
||||||
static void remove_request_buffer_from_map (void* ptr);
|
static void remove_request_buffer_from_map (pthread_t);
|
||||||
|
|
||||||
std::list<InvalidationRecord*> trash;
|
std::list<InvalidationRecord*> trash;
|
||||||
|
|
||||||
|
@ -115,9 +113,9 @@ private:
|
||||||
static Glib::Threads::Private<EventLoop> thread_event_loop;
|
static Glib::Threads::Private<EventLoop> thread_event_loop;
|
||||||
std::string _name;
|
std::string _name;
|
||||||
|
|
||||||
typedef std::map<std::string,ThreadBufferMapping> ThreadRequestBufferList;
|
typedef std::vector<ThreadBufferMapping> ThreadRequestBufferList;
|
||||||
static ThreadRequestBufferList thread_buffer_requests;
|
static ThreadRequestBufferList thread_buffer_requests;
|
||||||
static Glib::Threads::RWLock thread_buffer_requests_lock;
|
static Glib::Threads::Mutex thread_buffer_requests_lock;
|
||||||
|
|
||||||
struct RequestBufferSupplier {
|
struct RequestBufferSupplier {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user