forward port thread/abstract_ui changes from 2.X to 3.0
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 7 Feb 2011 18:21:50 +0000 (18:21 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 7 Feb 2011 18:21:50 +0000 (18:21 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8751 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/gtkmm2ext/gtk_ui.cc
libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
libs/pbd/pbd/abstract_ui.cc
libs/pbd/pbd/abstract_ui.h

index 1b697f4e4a5eb6e7171bc1ab8521f73a0b8c0906..dcce6b6c2854d611514242dac4aa89a6e5cabe2c 100644 (file)
@@ -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();
index a0ea1e86ad2f2e9e6687af27eecb90aca86c7d5f..49dd78a6d4ea77b6e619c949bc5a52d27321b25b 100644 (file)
@@ -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) {
index a769246f3874a895247e42aaaee52ea98676f689..4c13ec1b09f6a05b5c62e6251e1b05e8e22681ef 100644 (file)
 
 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 ();
 
index 943d9946663bb6922c06faae0a175916abf37c7e..0ee61eb7e184b5b4cb1e4f76c7e3dbd9e5aa8173 100644 (file)
@@ -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;