diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc index 1b697f4e4a..dcce6b6c28 100644 --- a/libs/gtkmm2ext/gtk_ui.cc +++ b/libs/gtkmm2ext/gtk_ui.cc @@ -51,6 +51,7 @@ using std::map; UI *UI::theGtkUI = 0; +BaseUI::RequestType Gtkmm2ext::NullMessage = BaseUI::new_request_type(); BaseUI::RequestType Gtkmm2ext::ErrorMessage = BaseUI::new_request_type(); BaseUI::RequestType Gtkmm2ext::TouchDisplay = BaseUI::new_request_type(); BaseUI::RequestType Gtkmm2ext::StateChange = BaseUI::new_request_type(); diff --git a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h index a0ea1e86ad..49dd78a6d4 100644 --- a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h +++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h @@ -50,6 +50,7 @@ namespace Gtkmm2ext { class TextViewer; +extern BaseUI::RequestType NullMessage; extern BaseUI::RequestType ErrorMessage; extern BaseUI::RequestType CallSlot; extern BaseUI::RequestType TouchDisplay; @@ -74,6 +75,10 @@ struct UIRequest : public BaseUI::BaseRequestObject { Transmitter::Channel chn; void *arg; const char *msg2; + + UIRequest () { + type = NullMessage; + } ~UIRequest () { if (type == ErrorMessage && msg) { diff --git a/libs/pbd/pbd/abstract_ui.cc b/libs/pbd/pbd/abstract_ui.cc index a769246f38..4c13ec1b09 100644 --- a/libs/pbd/pbd/abstract_ui.cc +++ b/libs/pbd/pbd/abstract_ui.cc @@ -10,11 +10,20 @@ using namespace std; -static void do_not_delete_the_request_buffer (void*) { } - template Glib::StaticPrivate::RequestBuffer> AbstractUI::per_thread_request_buffer; +template void +cleanup_request_buffer (void* ptr) +{ + RequestBuffer* rb = (RequestBuffer*) ptr; + + { + Glib::Mutex::Lock lm (rb->ui.request_buffer_map_lock); + rb->dead = true; + } +} + template AbstractUI::AbstractUI (const string& name) : BaseUI (name) @@ -35,14 +44,22 @@ AbstractUI::register_thread (string target_gui, pthread_t thread_ return; } - RequestBuffer* b = new RequestBuffer (num_requests); + RequestBuffer* b = per_thread_request_buffer.get(); + + if (b) { + /* thread already registered with this UI + */ + return; + } + + b = new RequestBuffer (num_requests, *this); { Glib::Mutex::Lock lm (request_buffer_map_lock); request_buffers[thread_id] = b; } - per_thread_request_buffer.set (b, do_not_delete_the_request_buffer); + per_thread_request_buffer.set (b, cleanup_request_buffer); } template RequestObject* @@ -83,23 +100,23 @@ AbstractUI::handle_ui_requests () for (i = request_buffers.begin(); i != request_buffers.end(); ++i) { - while (true) { - - /* we must process requests 1 by 1 because - the request may run a recursive main - event loop that will itself call - handle_ui_requests. when we return - from the request handler, we cannot - expect that the state of queued requests - is even remotely consistent with - the condition before we called it. - */ - - i->second->get_read_vector (&vec); - - if (vec.len[0] == 0) { - break; - } else { + while (true) { + + /* we must process requests 1 by 1 because + the request may run a recursive main + event loop that will itself call + handle_ui_requests. when we return + from the request handler, we cannot + expect that the state of queued requests + is even remotely consistent with + the condition before we called it. + */ + + i->second->get_read_vector (&vec); + + if (vec.len[0] == 0) { + break; + } else { if (vec.buf[0]->valid) { request_buffer_map_lock.unlock (); do_request (vec.buf[0]); @@ -109,9 +126,23 @@ AbstractUI::handle_ui_requests () } i->second->increment_read_ptr (1); } - } - } - } + } + } + } + + /* clean up any dead request buffers (their thread has exited) */ + + for (i = request_buffers.begin(); i != request_buffers.end(); ) { + if ((*i).second->dead) { + delete (*i).second; + RequestBufferMapIterator tmp = i; + ++tmp; + request_buffers.erase (i); + i = tmp; + } else { + ++i; + } + } request_buffer_map_lock.unlock (); diff --git a/libs/pbd/pbd/abstract_ui.h b/libs/pbd/pbd/abstract_ui.h index 943d994666..0ee61eb7e1 100644 --- a/libs/pbd/pbd/abstract_ui.h +++ b/libs/pbd/pbd/abstract_ui.h @@ -44,13 +44,21 @@ class AbstractUI : public BaseUI void call_slot (EventLoop::InvalidationRecord*, const boost::function&); Glib::Mutex& slot_invalidation_mutex() { return request_buffer_map_lock; } + Glib::Mutex request_buffer_map_lock; + protected: - typedef RingBufferNPT RequestBuffer; + struct RequestBuffer : public RingBufferNPT { + bool dead; + AbstractUI& ui; + RequestBuffer (uint32_t size, AbstractUI& uir) + : RingBufferNPT (size) + , dead (false) + , ui (uir) {} + }; typedef typename RequestBuffer::rw_vector RequestBufferVector; typedef typename std::map::iterator RequestBufferMapIterator; typedef std::map RequestBufferMap; - Glib::Mutex request_buffer_map_lock; RequestBufferMap request_buffers; static Glib::StaticPrivate per_thread_request_buffer;