summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/gtk_ui.h5
-rw-r--r--libs/pbd/pbd/abstract_ui.cc79
-rw-r--r--libs/pbd/pbd/abstract_ui.h12
4 files changed, 71 insertions, 26 deletions
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<typename R>
Glib::StaticPrivate<typename AbstractUI<R>::RequestBuffer> AbstractUI<R>::per_thread_request_buffer;
+template<typename RequestBuffer> void
+cleanup_request_buffer (void* ptr)
+{
+ RequestBuffer* rb = (RequestBuffer*) ptr;
+
+ {
+ Glib::Mutex::Lock lm (rb->ui.request_buffer_map_lock);
+ rb->dead = true;
+ }
+}
+
template <typename RequestObject>
AbstractUI<RequestObject>::AbstractUI (const string& name)
: BaseUI (name)
@@ -35,14 +44,22 @@ AbstractUI<RequestObject>::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<RequestBuffer>);
}
template <typename RequestObject> RequestObject*
@@ -83,23 +100,23 @@ AbstractUI<RequestObject>::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<RequestObject>::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<void()>&);
Glib::Mutex& slot_invalidation_mutex() { return request_buffer_map_lock; }
+ Glib::Mutex request_buffer_map_lock;
+
protected:
- typedef RingBufferNPT<RequestObject> RequestBuffer;
+ struct RequestBuffer : public RingBufferNPT<RequestObject> {
+ bool dead;
+ AbstractUI<RequestObject>& ui;
+ RequestBuffer (uint32_t size, AbstractUI<RequestObject>& uir)
+ : RingBufferNPT<RequestObject> (size)
+ , dead (false)
+ , ui (uir) {}
+ };
typedef typename RequestBuffer::rw_vector RequestBufferVector;
typedef typename std::map<pthread_t,RequestBuffer*>::iterator RequestBufferMapIterator;
typedef std::map<pthread_t,RequestBuffer*> RequestBufferMap;
- Glib::Mutex request_buffer_map_lock;
RequestBufferMap request_buffers;
static Glib::StaticPrivate<RequestBuffer> per_thread_request_buffer;