summaryrefslogtreecommitdiff
path: root/libs/pbd/pbd
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-03-30 15:18:43 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-03-30 15:18:43 +0000
commit14b0ca31bcb62e5b7e9e77634ef9cd2e8cf65800 (patch)
tree494bcf5351ff29d9981c22450863982b93a91a71 /libs/pbd/pbd
parent10c257039df399fc5a9c383434ee19abab6199ed (diff)
handle deletion of UI objects between the time that a callback is queued with the UI event loop and the execution of the callback (intrusive, big)
git-svn-id: svn://localhost/ardour2/branches/3.0@6807 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/pbd/pbd')
-rw-r--r--libs/pbd/pbd/abstract_ui.cc58
-rw-r--r--libs/pbd/pbd/abstract_ui.h3
-rw-r--r--libs/pbd/pbd/base_ui.h9
-rw-r--r--libs/pbd/pbd/event_loop.h31
-rw-r--r--libs/pbd/pbd/signals.h52
5 files changed, 109 insertions, 44 deletions
diff --git a/libs/pbd/pbd/abstract_ui.cc b/libs/pbd/pbd/abstract_ui.cc
index cc7010a415..71371fe4d9 100644
--- a/libs/pbd/pbd/abstract_ui.cc
+++ b/libs/pbd/pbd/abstract_ui.cc
@@ -61,11 +61,13 @@ AbstractUI<RequestObject>::get_request (RequestType rt)
}
vec.buf[0]->type = rt;
+ vec.buf[0]->valid = true;
return vec.buf[0];
}
RequestObject* req = new RequestObject;
req->type = rt;
+
return req;
}
@@ -98,10 +100,15 @@ AbstractUI<RequestObject>::handle_ui_requests ()
if (vec.len[0] == 0) {
break;
} else {
- request_buffer_map_lock.unlock ();
- do_request (vec.buf[0]);
- request_buffer_map_lock.lock ();
- i->second->increment_read_ptr (1);
+ if (vec.buf[0]->valid) {
+ request_buffer_map_lock.unlock ();
+ do_request (vec.buf[0]);
+ request_buffer_map_lock.lock ();
+ if (vec.buf[0]->invalidation) {
+ vec.buf[0]->invalidation->request = 0;
+ }
+ i->second->increment_read_ptr (1);
+ }
}
}
}
@@ -115,6 +122,30 @@ AbstractUI<RequestObject>::handle_ui_requests ()
while (!request_list.empty()) {
RequestObject* req = request_list.front ();
request_list.pop_front ();
+
+ /* We need to use this lock, because its the one
+ returned by slot_invalidation_mutex() and protects
+ against request invalidation.
+ */
+
+ request_buffer_map_lock.lock ();
+ if (!req->valid) {
+ delete req;
+ request_buffer_map_lock.unlock ();
+ continue;
+ }
+
+ /* we're about to execute this request, so its
+ too late for any invalidation. mark
+ the request as "done" before we start.
+ */
+
+ if (req->invalidation) {
+ req->invalidation->request = 0;
+ }
+
+ request_buffer_map_lock.unlock ();
+
lm.release ();
do_request (req);
@@ -152,14 +183,9 @@ AbstractUI<RequestObject>::send_request (RequestObject *req)
}
template<typename RequestObject> void
-AbstractUI<RequestObject>::call_slot (const boost::function<void()>& f)
+AbstractUI<RequestObject>::call_slot (InvalidationRecord* invalidation, const boost::function<void()>& f)
{
if (caller_is_self()) {
-#ifndef NDEBUG
- if (getenv ("DEBUG_THREADED_SIGNALS")) {
- std::cerr << "functor called in correct thread for " << name() << " , execute ...\n";
- }
-#endif
f ();
return;
}
@@ -171,11 +197,13 @@ AbstractUI<RequestObject>::call_slot (const boost::function<void()>& f)
}
req->the_slot = f;
-#ifndef NDEBUG
- if (getenv ("DEBUG_THREADED_SIGNALS")) {
- std::cerr << "functor called in wrong thread for " << name() << " (from " << pthread_name() << ") send request ...\n";
- }
-#endif
+ req->invalidation = invalidation;
+
+ if (invalidation) {
+ invalidation->request = req;
+ invalidation->event_loop = this;
+ }
+
send_request (req);
}
diff --git a/libs/pbd/pbd/abstract_ui.h b/libs/pbd/pbd/abstract_ui.h
index d04d62c463..943d994666 100644
--- a/libs/pbd/pbd/abstract_ui.h
+++ b/libs/pbd/pbd/abstract_ui.h
@@ -41,7 +41,8 @@ class AbstractUI : public BaseUI
virtual ~AbstractUI() {}
void register_thread (std::string, pthread_t, std::string, uint32_t num_requests);
- void call_slot (const boost::function<void()>&);
+ void call_slot (EventLoop::InvalidationRecord*, const boost::function<void()>&);
+ Glib::Mutex& slot_invalidation_mutex() { return request_buffer_map_lock; }
protected:
typedef RingBufferNPT<RequestObject> RequestBuffer;
diff --git a/libs/pbd/pbd/base_ui.h b/libs/pbd/pbd/base_ui.h
index 9e88be60f2..ccd4878cd9 100644
--- a/libs/pbd/pbd/base_ui.h
+++ b/libs/pbd/pbd/base_ui.h
@@ -48,15 +48,6 @@ class BaseUI : virtual public sigc::trackable, public PBD::EventLoop
bool ok() const { return _ok; }
- enum RequestType {
- range_guarantee = ~0
- };
-
- struct BaseRequestObject {
- RequestType type;
- boost::function<void()> the_slot;
- };
-
static RequestType new_request_type();
static RequestType CallSlot;
static RequestType Quit;
diff --git a/libs/pbd/pbd/event_loop.h b/libs/pbd/pbd/event_loop.h
index be98fcd852..088b061826 100644
--- a/libs/pbd/pbd/event_loop.h
+++ b/libs/pbd/pbd/event_loop.h
@@ -33,7 +33,34 @@ class EventLoop
EventLoop() {}
virtual ~EventLoop() {}
- virtual void call_slot (const boost::function<void()>&) = 0;
+ enum RequestType {
+ range_guarantee = ~0
+ };
+
+ struct BaseRequestObject;
+
+ struct InvalidationRecord {
+ BaseRequestObject* request;
+ PBD::EventLoop* event_loop;
+ const char* file;
+ int line;
+
+ InvalidationRecord() : request (0), event_loop (0) {}
+ };
+
+ static void* invalidate_request (void* data);
+
+ struct BaseRequestObject {
+ RequestType type;
+ bool valid;
+ InvalidationRecord* invalidation;
+ boost::function<void()> the_slot;
+
+ BaseRequestObject() : valid (true), invalidation (0) {}
+ };
+
+ virtual void call_slot (InvalidationRecord*, const boost::function<void()>&) = 0;
+ virtual Glib::Mutex& slot_invalidation_mutex() = 0;
static EventLoop* get_event_loop_for_thread();
static void set_event_loop_for_thread (EventLoop* ui);
@@ -45,4 +72,6 @@ class EventLoop
}
+#define MISSING_INVALIDATOR 0 // used to mark places where we fail to provide an invalidator
+
#endif /* __pbd_event_loop_h__ */
diff --git a/libs/pbd/pbd/signals.h b/libs/pbd/pbd/signals.h
index ffb0dcebb6..8e2b120b10 100644
--- a/libs/pbd/pbd/signals.h
+++ b/libs/pbd/pbd/signals.h
@@ -88,15 +88,17 @@ public:
}
void connect (ScopedConnectionList& clist,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, slot)));
+ clist.add_connection (_signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot)));
}
void connect (Connection& c,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, slot));
+ c = _signal.connect (boost::bind (&EventLoop::call_slot, event_loop, ir, slot));
}
typename SignalType::result_type operator()() {
@@ -125,20 +127,22 @@ public:
c = _signal.connect (slot);
}
- static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, A arg) {
- event_loop->call_slot (boost::bind (f, arg));
+ static void compositor (typename boost::function<void(A)> f, EventLoop* event_loop, EventLoop::InvalidationRecord* ir, A arg) {
+ event_loop->call_slot (ir, boost::bind (f, arg));
}
void connect (ScopedConnectionList& clist,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1)));
+ clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1)));
}
void connect (Connection& c,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- c = _signal.connect (boost::bind (&compositor, slot, event_loop, _1));
+ c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1));
}
@@ -168,20 +172,24 @@ public:
c = _signal.connect (slot);
}
- static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2) {
- event_loop->call_slot (boost::bind (f, arg1, arg2));
+ static void compositor (typename boost::function<void(A1,A2)> f, PBD::EventLoop* event_loop,
+ EventLoop::InvalidationRecord* ir,
+ A1 arg1, A2 arg2) {
+ event_loop->call_slot (ir, boost::bind (f, arg1, arg2));
}
void connect (ScopedConnectionList& clist,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2)));
+ clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2)));
}
void connect (Connection& c,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- c = _signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2));
+ c = _signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2) {
@@ -210,20 +218,24 @@ public:
c = _signal.connect (slot);
}
- static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2, A3 arg3) {
- event_loop->call_slot (boost::bind (f, arg1, arg2, arg3));
+ static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
+ EventLoop::InvalidationRecord* ir,
+ A1 arg1, A2 arg2, A3 arg3) {
+ event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3));
}
void connect (ScopedConnectionList& clist,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3)));
+ clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
}
void connect (Connection& c,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3)));
+ c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3)));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3) {
@@ -252,20 +264,24 @@ public:
c = _signal.connect (slot);
}
- static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
- event_loop->call_slot (boost::bind (f, arg1, arg2, arg3, arg4));
+ static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop,
+ EventLoop::InvalidationRecord* ir,
+ A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
+ event_loop->call_slot (ir, boost::bind (f, arg1, arg2, arg3, arg4));
}
void connect (ScopedConnectionList& clist,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3, _4)));
+ clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
}
void connect (Connection& c,
+ PBD::EventLoop::InvalidationRecord* ir,
const typename SignalType::slot_function_type& slot,
PBD::EventLoop* event_loop) {
- c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3, _4)));
+ c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, ir, _1, _2, _3, _4)));
}
typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {