enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / libs / pbd / pbd / abstract_ui.cc
index 116a82745261100674d26e2b4501af8bc128bd0b..6f03f2554e6b257e7c37f0db74f6de73a28534ab 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <unistd.h>
 #include <iostream>
+#include <algorithm>
 
 #include "pbd/stacktrace.h"
 #include "pbd/abstract_ui.h"
@@ -25,7 +26,7 @@
 #include "pbd/failed_constructor.h"
 #include "pbd/debug.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 #ifdef COMPILER_MSVC
 #include <ardourext/misc.h>  // Needed for 'DECLARE_DEFAULT_COMPARISONS'. Objects in an STL container can be
@@ -53,7 +54,7 @@ cleanup_request_buffer (void* ptr)
         * a request. If the UI has finished processing requests, then
         * we will leak this buffer object.
         */
-
+       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("thread \"%1\" exits: marking request buffer as dead @ %2\n", pthread_name(), rb));
        rb->dead = true;
 }
 
@@ -194,6 +195,8 @@ AbstractUI<RequestObject>::handle_ui_requests ()
 
        request_buffer_map_lock.lock ();
 
+       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1 check %2 request buffers for requests\n", event_loop_name(), request_buffers.size()));
+
        for (i = request_buffers.begin(); i != request_buffers.end(); ++i) {
 
                while (true) {
@@ -210,16 +213,39 @@ AbstractUI<RequestObject>::handle_ui_requests ()
 
                        i->second->get_read_vector (&vec);
 
+                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1 reading requests from RB[%2] @ %5, requests = %3 + %4\n",
+                                                                            event_loop_name(), std::distance (request_buffers.begin(), i), vec.len[0], vec.len[1], i->second));
+
                        if (vec.len[0] == 0) {
                                break;
                        } else {
                                if (vec.buf[0]->valid) {
+                                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: valid request, unlocking before calling\n", event_loop_name()));
                                        request_buffer_map_lock.unlock ();
+                                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: valid request, calling ::do_request()\n", event_loop_name()));
                                        do_request (vec.buf[0]);
+
+                                       /* if the request was CallSlot, then we need to ensure that we reset the functor in the request, in case it
+                                        * held a shared_ptr<>. Failure to do so can lead to dangling references to objects passed to PBD::Signals.
+                                        *
+                                        * Note that this method (::handle_ui_requests()) is by definition called from the event loop thread, so
+                                        * caller_is_self() is true, which means that the execution of the functor has definitely happened after
+                                        * do_request() returns and we no longer need the functor for any reason.
+                                        */
+
+                                       if (vec.buf[0]->type == CallSlot) {
+                                               vec.buf[0]->the_slot = 0;
+                                       }
+
                                        request_buffer_map_lock.lock ();
                                        if (vec.buf[0]->invalidation) {
+                                               DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: removing invalidation record for that request\n", event_loop_name()));
                                                vec.buf[0]->invalidation->requests.remove (vec.buf[0]);
+                                       } else {
+                                               DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: no invalidation record for that request\n", event_loop_name()));
                                        }
+                               } else {
+                                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, "invalid request, ignoring\n");
                                }
                                i->second->increment_read_ptr (1);
                        }
@@ -232,10 +258,13 @@ 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";
+                       /* remove it from the EventLoop static map of all request buffers */
+                       EventLoop::remove_request_buffer_from_map ((*i).second);
+                       /* delete it */
                        delete (*i).second;
                        RequestBufferMapIterator tmp = i;
                        ++tmp;
+                       /* remove it from this thread's list of request buffers */
                        request_buffers.erase (i);
                        i = tmp;
                } else {
@@ -354,7 +383,7 @@ AbstractUI<RequestObject>::send_request (RequestObject *req)
                RequestBuffer* rbuf = per_thread_request_buffer.get ();
 
                if (rbuf != 0) {
-                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1/%2 send per-thread request type %3\n", event_loop_name(), pthread_name(), req->type));
+                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1/%2 send per-thread request type %3 using ringbuffer @ %4\n", event_loop_name(), pthread_name(), req->type, rbuf));
                        rbuf->increment_write_ptr (1);
                } else {
                        /* no per-thread buffer, so just use a list with a lock so that it remains
@@ -415,7 +444,7 @@ AbstractUI<RequestObject>::call_slot (InvalidationRecord* invalidation, const bo
 template<typename RequestObject> void*
 AbstractUI<RequestObject>::request_buffer_factory (uint32_t num_requests)
 {
-       RequestBuffer*  mcr = new RequestBuffer (num_requests);
+       RequestBuffer*  mcr = new RequestBuffer (num_requests); // leaks
        per_thread_request_buffer.set (mcr);
        return mcr;
 }