switch to use boost::function for UI::call_slot operations, to avoid a serious thread safety issue with libsigc++
git-svn-id: svn://localhost/ardour2/branches/3.0@6355 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
64dc5427e4
commit
401c7091c8
@ -611,13 +611,13 @@ class Session : public PBD::StatefulDestructible, public SessionEventManager, pu
|
||||
bool soloing() const { return _non_soloed_outs_muted; }
|
||||
bool listening() const { return _listen_cnt > 0; }
|
||||
|
||||
static const sigc::slot<void,SessionEvent*> rt_cleanup;
|
||||
static const SessionEvent::RTeventCallback rt_cleanup;
|
||||
|
||||
void set_solo (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
|
||||
void set_just_one_solo (boost::shared_ptr<Route>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup);
|
||||
void set_mute (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
|
||||
void set_listen (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
|
||||
void set_record_enable (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
|
||||
void set_solo (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_just_one_solo (boost::shared_ptr<Route>, bool, SessionEvent::RTeventCallback after = rt_cleanup);
|
||||
void set_mute (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_listen (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_record_enable (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
|
||||
sigc::signal<void,bool> SoloActive;
|
||||
sigc::signal<void> SoloChanged;
|
||||
@ -1471,7 +1471,7 @@ class Session : public PBD::StatefulDestructible, public SessionEventManager, pu
|
||||
gint _have_rec_enabled_diskstream;
|
||||
|
||||
/* realtime "apply to set of routes" operations */
|
||||
SessionEvent* get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override,
|
||||
SessionEvent* get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override,
|
||||
void (Session::*method) (boost::shared_ptr<RouteList>, bool, bool));
|
||||
|
||||
void rt_set_solo (boost::shared_ptr<RouteList>, bool yn, bool group_override);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define __ardour_session_event_h__
|
||||
|
||||
#include <list>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <sigc++/signal.h>
|
||||
|
||||
@ -66,9 +67,13 @@ struct SessionEvent {
|
||||
bool second_yes_or_no;
|
||||
};
|
||||
|
||||
boost::shared_ptr<RouteList> routes;
|
||||
sigc::slot<void> rt_slot; /* what to call in RT context */
|
||||
sigc::slot<void,SessionEvent*> rt_return; /* called after rt_slot, with this event as an argument */
|
||||
/* 4 members to handle a multi-group event handled in RT context */
|
||||
|
||||
typedef boost::function<void (SessionEvent*)> RTeventCallback;
|
||||
|
||||
boost::shared_ptr<RouteList> routes; /* apply to */
|
||||
boost::function<void (void)> rt_slot; /* what to call in RT context */
|
||||
RTeventCallback rt_return; /* called after rt_slot, with this event as an argument */
|
||||
PBD::UICallback* ui;
|
||||
|
||||
std::list<AudioRange> audio_range;
|
||||
|
@ -1419,7 +1419,6 @@ void
|
||||
Region::source_deleted (boost::shared_ptr<Source>)
|
||||
{
|
||||
_sources.clear ();
|
||||
drop_references ();
|
||||
}
|
||||
|
||||
vector<string>
|
||||
|
@ -118,7 +118,7 @@ sigc::signal<void> Session::AutoBindingOff;
|
||||
sigc::signal<void, std::string, std::string> Session::Exported;
|
||||
|
||||
static void clean_up_session_event (SessionEvent* ev) { delete ev; }
|
||||
const sigc::slot<void,SessionEvent*> Session::rt_cleanup (sigc::ptr_fun (&clean_up_session_event));
|
||||
const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event);
|
||||
|
||||
Session::Session (AudioEngine &eng,
|
||||
const string& fullpath,
|
||||
|
@ -16,6 +16,8 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/compose.h"
|
||||
|
||||
@ -31,11 +33,11 @@ using namespace ARDOUR;
|
||||
using namespace Glib;
|
||||
|
||||
SessionEvent*
|
||||
Session::get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override,
|
||||
Session::get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override,
|
||||
void (Session::*method) (boost::shared_ptr<RouteList>, bool, bool))
|
||||
{
|
||||
SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
|
||||
ev->rt_slot = bind (sigc::mem_fun (*this, method), rl, yn, group_override);
|
||||
ev->rt_slot = boost::bind (method, this, rl, yn, group_override);
|
||||
ev->rt_return = after;
|
||||
ev->ui = UICallback::get_ui_for_thread ();
|
||||
|
||||
@ -43,7 +45,7 @@ Session::get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override)
|
||||
Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
|
||||
{
|
||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo));
|
||||
}
|
||||
@ -61,7 +63,7 @@ Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, bool group_overr
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, sigc::slot<void,SessionEvent*> after)
|
||||
Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, SessionEvent::RTeventCallback after)
|
||||
{
|
||||
/* its a bit silly to have to do this, but it keeps the API for this public method sane (we're
|
||||
only going to solo one route) and keeps our ability to use get_rt_event() for the internal
|
||||
@ -92,7 +94,7 @@ Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, b
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override)
|
||||
Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
|
||||
{
|
||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_listen));
|
||||
}
|
||||
@ -110,7 +112,7 @@ Session::rt_set_listen (boost::shared_ptr<RouteList> rl, bool yn, bool group_ove
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override)
|
||||
Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
|
||||
{
|
||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_mute));
|
||||
}
|
||||
@ -128,7 +130,7 @@ Session::rt_set_mute (boost::shared_ptr<RouteList> rl, bool yn, bool group_overr
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_record_enable (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override)
|
||||
Session::set_record_enable (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
|
||||
{
|
||||
if (!writable()) {
|
||||
return;
|
||||
@ -161,7 +163,7 @@ Session::process_rtop (SessionEvent* ev)
|
||||
ev->rt_slot ();
|
||||
|
||||
if (ev->ui) {
|
||||
ev->ui->call_slot (bind (ev->rt_return, ev));
|
||||
ev->ui->call_slot (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);
|
||||
|
@ -140,10 +140,10 @@ AbstractUI<RequestObject>::send_request (RequestObject *req)
|
||||
}
|
||||
|
||||
template<typename RequestObject> void
|
||||
AbstractUI<RequestObject>::call_slot (sigc::slot<void> elSlot)
|
||||
AbstractUI<RequestObject>::call_slot (const boost::function<void()>& f)
|
||||
{
|
||||
if (caller_is_self()) {
|
||||
elSlot ();
|
||||
f ();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ AbstractUI<RequestObject>::call_slot (sigc::slot<void> elSlot)
|
||||
return;
|
||||
}
|
||||
|
||||
req->the_slot = elSlot;
|
||||
req->the_slot = f;
|
||||
send_request (req);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ class AbstractUI : public BaseUI
|
||||
virtual ~AbstractUI() {}
|
||||
|
||||
void register_thread (std::string, pthread_t, std::string, uint32_t num_requests);
|
||||
void call_slot (sigc::slot<void> el_slot);
|
||||
void call_slot (const boost::function<void()>&);
|
||||
|
||||
protected:
|
||||
typedef RingBufferNPT<RequestObject> RequestBuffer;
|
||||
|
@ -54,7 +54,7 @@ class BaseUI : virtual public sigc::trackable, public PBD::UICallback
|
||||
|
||||
struct BaseRequestObject {
|
||||
RequestType type;
|
||||
sigc::slot<void> the_slot;
|
||||
boost::function<void()> the_slot;
|
||||
};
|
||||
|
||||
static RequestType new_request_type();
|
||||
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2009 Paul Davis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __pbd_closure_h__
|
||||
#define __pbd_closure_h__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* Here we implement thread-safe but lifetime-unsafe closures (aka "functor"), which
|
||||
* wrap an object and one of its methods, plus zero-or-more arguments, in a convenient,
|
||||
* ready to use package.
|
||||
*
|
||||
* These differ from sigc::slot<> in that they are totally non-invasive with
|
||||
* respect to the objects referenced by the closure. There is no requirement
|
||||
* that the object be derived from any particular base class, and nothing
|
||||
* will be done to the object during the creation of the closure, or its deletion,
|
||||
* or at any time other than when the object's method is invoked via
|
||||
* Closure::operator(). As a result, the closure can be constructed and deleted without
|
||||
* concerns for thread safety. If the object method is thread-safe, then the closure
|
||||
* can also be invoked in a thread safe fashion.
|
||||
*
|
||||
* However, this also means that the closure is not safe against lifetime
|
||||
* management issues - if the referenced object is deleted before the closure,
|
||||
* and then closure is invoked via operator(), the results are undefined (but
|
||||
* will almost certainly be bad). This class should therefore be used only
|
||||
* where you can guarantee that the referred-to object will outlive the
|
||||
* life of the closure.
|
||||
*/
|
||||
|
||||
namespace PBD {
|
||||
|
||||
struct ClosureBaseImpl {
|
||||
ClosureBaseImpl() { g_atomic_int_set (&_ref, 0); }
|
||||
|
||||
ClosureBaseImpl* ref() { g_atomic_int_inc (&_ref); return this; }
|
||||
void unref() { if (g_atomic_int_dec_and_test (&_ref)) delete this; }
|
||||
|
||||
virtual void operator() () = 0;
|
||||
|
||||
protected:
|
||||
virtual ~ClosureBaseImpl() { }
|
||||
|
||||
private:
|
||||
gint _ref;
|
||||
};
|
||||
|
||||
struct Closure {
|
||||
Closure () : impl (0) {}
|
||||
Closure (ClosureBaseImpl* i) : impl (i->ref()) {}
|
||||
Closure (const Closure& other) : impl (other.impl ? other.impl->ref() : 0) {}
|
||||
|
||||
Closure& operator= (const Closure& other) {
|
||||
if (&other == this) {
|
||||
return *this;
|
||||
}
|
||||
if (impl) {
|
||||
impl->unref();
|
||||
}
|
||||
if (other.impl) {
|
||||
impl = other.impl->ref();
|
||||
} else {
|
||||
impl = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~Closure () { if (impl) { impl->unref(); } }
|
||||
|
||||
/* will crash if impl is unset */
|
||||
void operator() () const { (*impl)(); }
|
||||
|
||||
protected:
|
||||
ClosureBaseImpl* impl;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ClosureImpl0 : public ClosureBaseImpl {
|
||||
ClosureImpl0 (T& obj, void (T::*m)())
|
||||
: object (obj), method (m) {}
|
||||
void operator() () { (object.*method)(); }
|
||||
private:
|
||||
T& object;
|
||||
void (T::*method)();
|
||||
};
|
||||
|
||||
template<typename T, typename A1>
|
||||
struct ClosureImpl1 : public ClosureBaseImpl
|
||||
{
|
||||
ClosureImpl1 (T& obj, void (T::*m)(A1), A1 arg)
|
||||
: object (obj), method (m), arg1 (arg) {}
|
||||
void operator() () { (object.*method) (arg1); }
|
||||
|
||||
private:
|
||||
T& object;
|
||||
void (T::*method)(A1);
|
||||
A1 arg1;
|
||||
};
|
||||
|
||||
template<typename T, typename A1, typename A2>
|
||||
struct ClosureImpl2 : public ClosureBaseImpl
|
||||
{
|
||||
ClosureImpl2 (T& obj, void (T::*m)( A1, A2), A1 arga, A2 argb)
|
||||
: object (obj), method (m), arg1 (arga), arg2 (argb) {}
|
||||
void operator() () { (object.*method) (arg1, arg2); }
|
||||
|
||||
private:
|
||||
T& object;
|
||||
void (T::*method)(A1, A2);
|
||||
A1 arg1;
|
||||
A2 arg2;
|
||||
};
|
||||
|
||||
template<typename T, typename A1, typename A2, typename A3>
|
||||
struct ClosureImpl3 : public ClosureBaseImpl
|
||||
{
|
||||
ClosureImpl3 (T& obj, void (T::*m)( A1, A2, A3), A1 arga, A2 argb, A3 argc)
|
||||
: object (obj), method (m), arg1 (arga), arg2 (argb), arg3 (argc) {}
|
||||
void operator() () { (object.*method) (arg1, arg2, arg3); }
|
||||
|
||||
private:
|
||||
T& object;
|
||||
void (T::*method)(A1, A2, A3);
|
||||
A1 arg1;
|
||||
A2 arg2;
|
||||
A3 arg3;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Closure closure (T& t, void (T::*m)()) {return Closure (new ClosureImpl0<T> (t,m)); }
|
||||
|
||||
template<typename T, typename A>
|
||||
Closure closure (T& t, void (T::*m)(A), A a) { return Closure (new ClosureImpl1<T,A>(t,m,a)); }
|
||||
|
||||
template<typename T, typename A1, typename A2>
|
||||
Closure closure (T& t, void (T::*m)(A1,A2), A1 a1, A2 a2) { return Closure (new ClosureImpl2<T,A1,A2>(t,m, a1, a2)); }
|
||||
|
||||
template<typename T, typename A1, typename A2, typename A3>
|
||||
Closure closure (T& t, void (T::*m)(A1, A2, A3), A1 a1, A2 a2, A3 a3) { return Closure (new ClosureImpl3<T,A1,A2,A3>(t,m , a1, a2, a3)); }
|
||||
|
||||
/*--- CALL TIME CLOSURES : these accept arguments at run time */
|
||||
|
||||
template<typename A>
|
||||
struct CTClosureBaseImpl : ClosureBaseImpl {
|
||||
CTClosureBaseImpl() {}
|
||||
|
||||
virtual void operator() () { operator() (A()); }
|
||||
virtual void operator() (A arg) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CTClosureBaseImpl() { }
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
struct CTClosure : public Closure {
|
||||
CTClosure() {}
|
||||
CTClosure (CTClosureBaseImpl<A>* i) : Closure (i) {}
|
||||
CTClosure (const CTClosure& other) : Closure (other) {}
|
||||
|
||||
/* will crash if impl is unset */
|
||||
void operator() (A arg) const { (*(dynamic_cast<CTClosureBaseImpl<A>*> (impl))) (arg); }
|
||||
};
|
||||
|
||||
template<typename T, typename A>
|
||||
struct CTClosureImpl1 : public CTClosureBaseImpl<A>
|
||||
{
|
||||
CTClosureImpl1 (T& obj, void (T::*m)(A))
|
||||
: object (obj), method (m) {}
|
||||
void operator() (A call_time_arg) { (object.*method) (call_time_arg); }
|
||||
|
||||
private:
|
||||
T& object;
|
||||
void (T::*method)(A);
|
||||
};
|
||||
|
||||
/* functor wraps a method that takes 1 arg provided at call-time */
|
||||
|
||||
template<typename T, typename A>
|
||||
CTClosure<A> closure (T& t, void (T::*m)(A)) { return CTClosure<A> (new CTClosureImpl1<T,A>(t,m)); }
|
||||
|
||||
}
|
||||
|
||||
#endif /* __pbd_closure_h__ */
|
@ -20,8 +20,8 @@
|
||||
#ifndef __pbd_ui_callback_h__
|
||||
#define __pbd_ui_callback_h__
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <glibmm/thread.h>
|
||||
#include <sigc++/slot.h>
|
||||
|
||||
namespace PBD
|
||||
{
|
||||
@ -32,7 +32,7 @@ class UICallback
|
||||
UICallback() {}
|
||||
virtual ~UICallback() {}
|
||||
|
||||
virtual void call_slot (sigc::slot<void> theSlot) = 0;
|
||||
virtual void call_slot (const boost::function<void()>&) = 0;
|
||||
|
||||
static UICallback* get_ui_for_thread();
|
||||
static void set_ui_for_thread (UICallback* ui);
|
||||
|
Loading…
Reference in New Issue
Block a user