Add a trash pool for invalidation requests.
authorRobin Gareus <robin@gareus.org>
Wed, 14 Dec 2016 21:38:37 +0000 (22:38 +0100)
committerRobin Gareus <robin@gareus.org>
Wed, 14 Dec 2016 21:39:25 +0000 (22:39 +0100)
While EventLoop::invalidate_request() does invalidate request in the
request-list. It does *not* invalidate requests in the
per-thread-request-ringbuffer(s).
The invalidation record cannot be deleted in EventLoop::invalidate_request
see 6b5891a78f.

libs/pbd/event_loop.cc
libs/pbd/pbd/abstract_ui.cc
libs/pbd/pbd/event_loop.h

index 0baba2835a4e04ab3cec41b34a61880ddbc854b3..aae0c21a08cf740d8f0a33f91fa47a8e3401bf2b 100644 (file)
@@ -95,8 +95,9 @@ EventLoop::invalidate_request (void* data)
                                (*i)->invalidation = 0;
                        }
                }
-               // should this not always be deleted, regardless if there's an event_loop?
-               delete ir;
+               // This invalidation record may still be in-use in per-thread-request-ringbuffer.
+               // it cannot be deleted here,
+               ir->event_loop->trash.push_back(ir);
        } else {
                DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("EventLoop::invalidate_request no event-loop for invalidation %1\n", ir));
        }
index db63c3f96d10d48fd72ce575ca38ea691512379e..db7ce38a6460771ba70072ceb630c8b87a3c484c 100644 (file)
@@ -218,6 +218,7 @@ AbstractUI<RequestObject>::handle_ui_requests ()
                        if (vec.len[0] == 0) {
                                break;
                        } else {
+                               bool alive = true;
                                if (vec.buf[0]->valid ()) {
                                        /* We first need to remove the event from the list.
                                         * If the event results in object destruction, PBD::EventLoop::invalidate_request
@@ -225,6 +226,7 @@ AbstractUI<RequestObject>::handle_ui_requests ()
                                         */
                                        DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: remove request %2 from its invalidation list %3\n", event_loop_name(), vec.buf[0], vec.buf[0]->invalidation));
                                        if (vec.buf[0]->invalidation) {
+                                               alive = std::find (trash.begin(), trash.end(), vec.buf[0]->invalidation) == trash.end();
                                                DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: removing invalidation record for that request\n", event_loop_name()));
                                                if (vec.buf[0]->invalidation->event_loop && vec.buf[0]->invalidation->event_loop != this) {
                                                        vec.buf[0]->invalidation->event_loop->slot_invalidation_mutex().lock ();
@@ -240,8 +242,12 @@ AbstractUI<RequestObject>::handle_ui_requests ()
                                        DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: valid request, unlocking before calling\n", event_loop_name()));
                                        rbml.release ();
 
-                                       DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: valid request, calling ::do_request()\n", event_loop_name()));
-                                       do_request (vec.buf[0]);
+                                       if (alive) {
+                                               DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: valid request, calling ::do_request()\n", event_loop_name()));
+                                               do_request (vec.buf[0]);
+                                       } else {
+                                               DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1: skipping invalidated request\n", event_loop_name()));
+                                       }
 
                                        /* 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.
@@ -264,8 +270,6 @@ AbstractUI<RequestObject>::handle_ui_requests ()
                }
        }
 
-       /* clean up any dead request buffers (their thread has exited) */
-
        assert (rbml.locked ());
        for (i = request_buffers.begin(); i != request_buffers.end(); ) {
                if ((*i).second->dead) {
@@ -370,6 +374,15 @@ AbstractUI<RequestObject>::handle_ui_requests ()
                rbml.acquire();
        }
 
+       /* clean up any dead invalidation records (object was deleted) */
+       trash.sort();
+       trash.unique();
+       for (std::list<InvalidationRecord*>::const_iterator r = trash.begin(); r != trash.end(); ++r) {
+               DEBUG_TRACE (PBD::DEBUG::AbstractUI, string_compose ("%1 drop invalidation trash %2\n", event_loop_name(), *r));
+               delete *r;
+       }
+       trash.clear ();
+
        rbml.release ();
 }
 
index 6fd92c49c8be1bfa5cd199d9fe0b454425dc95cd..e84832ebcba71fae5022250d8e23819a35cb03d8 100644 (file)
@@ -99,6 +99,8 @@ public:
        static void pre_register (const std::string& emitting_thread_name, uint32_t num_requests);
        static void remove_request_buffer_from_map (void* ptr);
 
+       std::list<InvalidationRecord*> trash;
+
 private:
        static Glib::Threads::Private<EventLoop> thread_event_loop;
        std::string _name;