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
This commit is contained in:
Paul Davis 2010-03-30 15:18:43 +00:00
parent 10c257039d
commit 14b0ca31bc
87 changed files with 468 additions and 349 deletions

View file

@ -2076,9 +2076,7 @@ int
AudioDiskstream::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
{
while (how_many-- && !c->empty()) {
// FIXME: crash (thread safe with RCU?)
// memory leak, when disabled.... :(
//delete c->back();
delete c->back();
c->pop_back();
interpolation.remove_channel_from ();
}
@ -2324,9 +2322,7 @@ AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_si
AudioDiskstream::ChannelInfo::~ChannelInfo ()
{
if (write_source) {
write_source.reset ();
}
write_source.reset ();
delete [] speed_buffer;
speed_buffer = 0;

View file

@ -159,7 +159,7 @@ AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, Connection& c
*/
if (!(ret = _peaks_built)) {
PeaksReady.connect (connect_here_if_not, doThisWhenReady, event_loop);
PeaksReady.connect (connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
}
return ret;

View file

@ -172,7 +172,7 @@ RCConfiguration::save_state()
const string rcfile = rcfile_path.to_string();
// this test seems bogus?
if (rcfile.length()) {
if (!rcfile.empty()) {
XMLTree tree;
tree.set_root (&get_state());
if (!tree.write (rcfile.c_str())){

View file

@ -191,7 +191,6 @@ Session::silent_process_routes (nframes_t nframes, bool& need_butler)
void
Session::get_diskstream_statistics ()
{
int dret;
float pworst = 1.0f;
float cworst = 1.0f;

View file

@ -163,7 +163,7 @@ Session::process_rtop (SessionEvent* ev)
ev->rt_slot ();
if (ev->event_loop) {
ev->event_loop->call_slot (boost::bind (ev->rt_return, ev));
ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
} else {
warning << string_compose ("programming error: %1", X_("Session RT event queued from thread without a UI - cleanup in RT thread!")) << endmsg;
ev->rt_return (ev);

View file

@ -369,6 +369,19 @@ UI::idle_add (int (*func)(void *), void *arg)
/* END abstract_ui interfaces */
PBD::EventLoop::InvalidationRecord*
__invalidator (sigc::trackable& trackable, const char* file, int line)
{
PBD::EventLoop::InvalidationRecord* ir = new PBD::EventLoop::InvalidationRecord;
ir->file = file;
ir->line = line;
trackable.add_destroy_notify_callback (ir, PBD::EventLoop::invalidate_request);
return ir;
}
void
UI::do_request (UIRequest* req)
{

View file

@ -83,13 +83,13 @@ PopUp::remove ()
gtk_idle_add (idle_delete, this);
}
}
#define ENSURE_GUI_THREAD(slot) \
if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {\
Gtkmm2ext::UI::instance()->call_slot ((slot));\
Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, (slot)); \
return;\
}
void
PopUp::touch ()
{

View file

@ -1,6 +1,9 @@
#include <iostream>
#include "pbd/event_loop.h"
#include "pbd/stacktrace.h"
using namespace PBD;
using namespace std;
Glib::StaticPrivate<EventLoop> EventLoop::thread_event_loop;
@ -17,3 +20,29 @@ EventLoop::set_event_loop_for_thread (EventLoop* loop)
thread_event_loop.set (loop, do_not_delete_the_loop_pointer);
}
void*
EventLoop::invalidate_request (void* data)
{
InvalidationRecord* ir = (InvalidationRecord*) data;
if (ir->event_loop) {
Glib::Mutex::Lock lm (ir->event_loop->slot_invalidation_mutex());
if (ir->request) {
cerr << "Object deleted had outstanding event loop request, IR created @ "
<< ir->file << ':' << ir->line
<< endl;
ir->request->valid = false;
ir->request->invalidation = 0;
} else {
cerr << "No queued request associated with object deletion from "
<< ir->file << ':' << ir->line
<< endl;
}
delete ir;
}
return 0;
}

View file

@ -8,15 +8,22 @@ using namespace PBD;
LocaleGuard::LocaleGuard (const char* str)
{
old = strdup (setlocale (LC_NUMERIC, NULL));
if (strcmp (old, str)) {
setlocale (LC_NUMERIC, str);
}
old = setlocale (LC_NUMERIC, NULL);
if (old) {
old = strdup (old);
if (strcmp (old, str)) {
setlocale (LC_NUMERIC, str);
}
}
}
LocaleGuard::~LocaleGuard ()
{
setlocale (LC_NUMERIC, old);
free ((char*)old);
if (old) {
free ((char*)old);
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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__ */

View file

@ -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) {

View file

@ -52,7 +52,7 @@ ControlProtocol::ControlProtocol (Session& s, string str, EventLoop* evloop)
_active = false;
session->RouteAdded.connect (*this, boost::protect (boost::bind (&ControlProtocol::add_strip, this, _1)), _event_loop);
session->RouteAdded.connect (*this, MISSING_INVALIDATOR, boost::protect (boost::bind (&ControlProtocol::add_strip, this, _1)), _event_loop);
}
ControlProtocol::~ControlProtocol ()

View file

@ -85,8 +85,8 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
Session::SendFeedback.connect (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
Route::RemoteControlIDChange.connect (*this, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
reload_maps ();
}

View file

@ -540,23 +540,23 @@ void
MackieControlProtocol::connect_session_signals()
{
// receive routes added
session->RouteAdded.connect(session_connections, ui_bind (&MackieControlProtocol::notify_route_added, this, _1), midi_ui_context());
session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_route_added, this, _1), midi_ui_context());
// receive record state toggled
session->RecordStateChanged.connect(session_connections, ui_bind (&MackieControlProtocol::notify_record_state_changed, this), midi_ui_context());
session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_record_state_changed, this), midi_ui_context());
// receive transport state changed
session->TransportStateChange.connect(session_connections, ui_bind (&MackieControlProtocol::notify_transport_state_changed, this), midi_ui_context());
session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_transport_state_changed, this), midi_ui_context());
// receive punch-in and punch-out
Config->ParameterChanged.connect(session_connections, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
session->config.ParameterChanged.connect (session_connections, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
// receive rude solo changed
session->SoloActive.connect(session_connections, ui_bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), midi_ui_context());
session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), midi_ui_context());
// make sure remote id changed signals reach here
// see also notify_route_added
Sorted sorted = get_sorted_routes();
for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) {
(*it)->RemoteControlIDChanged.connect (route_connections, ui_bind(&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
(*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind(&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
}
}
@ -1417,7 +1417,7 @@ MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl)
typedef ARDOUR::RouteList ARS;
for (ARS::iterator it = rl.begin(); it != rl.end(); ++it) {
(*it)->RemoteControlIDChanged.connect (route_connections, ui_bind (&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
(*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
}
}

View file

@ -37,35 +37,35 @@ using namespace std;
void RouteSignal::connect()
{
if (_strip.has_solo()) {
_route->solo_control()->Changed.connect(connections, ui_bind (&MackieControlProtocol::notify_solo_changed, &_mcp, this), midi_ui_context());
_route->solo_control()->Changed.connect(connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_solo_changed, &_mcp, this), midi_ui_context());
}
if (_strip.has_mute()) {
_route->mute_control()->Changed.connect(connections, ui_bind (&MackieControlProtocol::notify_mute_changed, &_mcp, this), midi_ui_context());
_route->mute_control()->Changed.connect(connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_mute_changed, &_mcp, this), midi_ui_context());
}
if (_strip.has_gain()) {
_route->gain_control()->Changed.connect(connections, ui_bind (&MackieControlProtocol::notify_gain_changed, &_mcp, this, false), midi_ui_context());
_route->gain_control()->Changed.connect(connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_gain_changed, &_mcp, this, false), midi_ui_context());
}
_route->PropertyChanged.connect (connections, ui_bind (&MackieControlProtocol::notify_property_changed, &_mcp, _1, this), midi_ui_context());
_route->PropertyChanged.connect (connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_property_changed, &_mcp, _1, this), midi_ui_context());
if (_route->panner()) {
_route->panner()->Changed.connect(connections, ui_bind (&MackieControlProtocol::notify_panner_changed, &_mcp, this, false), midi_ui_context());
_route->panner()->Changed.connect(connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_panner_changed, &_mcp, this, false), midi_ui_context());
for ( unsigned int i = 0; i < _route->panner()->npanners(); ++i ) {
_route->panner()->streampanner(i).Changed.connect (connections, ui_bind (&MackieControlProtocol::notify_panner_changed, &_mcp, this, false), midi_ui_context());
_route->panner()->streampanner(i).Changed.connect (connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_panner_changed, &_mcp, this, false), midi_ui_context());
}
}
boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
if (trk) {
trk->rec_enable_control()->Changed .connect(connections, ui_bind (&MackieControlProtocol::notify_record_enable_changed, &_mcp, this), midi_ui_context());
trk->rec_enable_control()->Changed .connect(connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_record_enable_changed, &_mcp, this), midi_ui_context());
}
// TODO this works when a currently-banked route is made inactive, but not
// when a route is activated which should be currently banked.
_route->active_changed.connect (connections, ui_bind (&MackieControlProtocol::notify_active_changed, &_mcp, this), midi_ui_context());
_route->active_changed.connect (connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_active_changed, &_mcp, this), midi_ui_context());
// TODO
// SelectedChanged

View file

@ -87,7 +87,7 @@ OSC::OSC (Session& s, uint32_t port)
// "Application Hooks"
session_loaded (s);
session->Exported.connect (*this, ui_bind (&OSC::session_exported, this, _1, _2), this);
session->Exported.connect (*this, MISSING_INVALIDATOR, ui_bind (&OSC::session_exported, this, _1, _2), this);
}
OSC::~OSC()
@ -101,7 +101,7 @@ OSC::do_request (OSCUIRequest* req)
{
if (req->type == CallSlot) {
call_slot (req->the_slot);
call_slot (MISSING_INVALIDATOR, req->the_slot);
} else if (req->type == Quit) {
@ -586,7 +586,7 @@ OSC::listen_to_route (boost::shared_ptr<Route> route, lo_address addr)
*/
if (!route_exists) {
route->DropReferences.connect (*this, boost::bind (&OSC::drop_route, this, boost::weak_ptr<Route> (route)), this);
route->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::drop_route, this, boost::weak_ptr<Route> (route)), this);
}
}

View file

@ -36,7 +36,7 @@ OSCControllable::OSCControllable (lo_address a, const std::string& p, boost::sha
, addr (a)
, path (p)
{
c->Changed.connect (changed_connection, boost::bind (&OSCControllable::send_change_message, this), OSC::instance());
c->Changed.connect (changed_connection, MISSING_INVALIDATOR, boost::bind (&OSCControllable::send_change_message, this), OSC::instance());
}
OSCControllable::~OSCControllable ()