remove recursive mutex from Playlist, replace with private regular mutex, force everyone to use Playlist::RegionLock to allow checking on lock handling if necessary; fix recursive use of lock in AudioPlaylist::read()

git-svn-id: svn://localhost/ardour2/branches/3.0@12131 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-05-01 16:19:51 +00:00
parent 77be4a2742
commit ac46e5edb4
4 changed files with 142 additions and 150 deletions

View File

@ -39,6 +39,7 @@
#include "pbd/stateful.h" #include "pbd/stateful.h"
#include "pbd/statefuldestructible.h" #include "pbd/statefuldestructible.h"
#include "pbd/sequence_property.h" #include "pbd/sequence_property.h"
#include "pbd/stacktrace.h"
#include "evoral/types.hpp" #include "evoral/types.hpp"
@ -231,7 +232,10 @@ public:
protected: protected:
struct RegionLock { struct RegionLock {
RegionLock (Playlist *pl, bool do_block_notify = true) : playlist (pl), block_notify (do_block_notify) { RegionLock (Playlist *pl, bool do_block_notify = true) : playlist (pl), block_notify (do_block_notify) {
playlist->region_lock.lock(); if (!playlist->region_lock.trylock()) {
std::cerr << "Lock for playlist " << pl->name() << " already held\n";
PBD::stacktrace (std::cerr, 10);
}
if (block_notify) { if (block_notify) {
playlist->delay_notifications(); playlist->delay_notifications();
} }
@ -246,8 +250,6 @@ public:
bool block_notify; bool block_notify;
}; };
friend class RegionLock;
RegionListProperty regions; /* the current list of regions in the playlist */ RegionListProperty regions; /* the current list of regions in the playlist */
std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */ std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
PBD::ScopedConnectionList region_state_changed_connections; PBD::ScopedConnectionList region_state_changed_connections;
@ -255,11 +257,6 @@ public:
int _sort_id; int _sort_id;
mutable gint block_notifications; mutable gint block_notifications;
mutable gint ignore_state_changes; mutable gint ignore_state_changes;
#ifdef HAVE_GLIB_THREADS_RECMUTEX
mutable Glib::Threads::RecMutex region_lock;
#else
mutable Glib::RecMutex region_lock;
#endif
std::set<boost::shared_ptr<Region> > pending_adds; std::set<boost::shared_ptr<Region> > pending_adds;
std::set<boost::shared_ptr<Region> > pending_removes; std::set<boost::shared_ptr<Region> > pending_removes;
RegionList pending_bounds; RegionList pending_bounds;
@ -303,6 +300,8 @@ public:
void _set_sort_id (); void _set_sort_id ();
boost::shared_ptr<RegionList> regions_touched_locked (framepos_t start, framepos_t end);
void notify_region_removed (boost::shared_ptr<Region>); void notify_region_removed (boost::shared_ptr<Region>);
void notify_region_added (boost::shared_ptr<Region>); void notify_region_added (boost::shared_ptr<Region>);
void notify_layering_changed (); void notify_layering_changed ();
@ -365,8 +364,11 @@ public:
*/ */
virtual void pre_uncombine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>) {} virtual void pre_uncombine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>) {}
private: private:
friend class RegionLock;
mutable Glib::Mutex region_lock;
private:
void setup_layering_indices (RegionList const &); void setup_layering_indices (RegionList const &);
void coalesce_and_check_crossfades (std::list<Evoral::Range<framepos_t> >); void coalesce_and_check_crossfades (std::list<Evoral::Range<framepos_t> >);
boost::shared_ptr<RegionList> find_regions_at (framepos_t); boost::shared_ptr<RegionList> find_regions_at (framepos_t);

View File

@ -186,16 +186,12 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr
its OK to block (for short intervals). its OK to block (for short intervals).
*/ */
#ifdef HAVE_GLIB_THREADS_RECMUTEX Playlist::RegionLock rl (this, false);
Glib::Threads::RecMutex::Lock lm (region_lock);
#else
Glib::RecMutex::Lock rm (region_lock);
#endif
/* Find all the regions that are involved in the bit we are reading, /* Find all the regions that are involved in the bit we are reading,
and sort them by descending layer and ascending position. and sort them by descending layer and ascending position.
*/ */
boost::shared_ptr<RegionList> all = regions_touched (start, start + cnt - 1); boost::shared_ptr<RegionList> all = regions_touched_locked (start, start + cnt - 1);
all->sort (ReadSorter ()); all->sort (ReadSorter ());
/* This will be a list of the bits of our read range that we have /* This will be a list of the bits of our read range that we have

View File

@ -107,11 +107,8 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec
its OK to block (for short intervals). its OK to block (for short intervals).
*/ */
#ifdef HAVE_GLIB_THREADS_RECMUTEX Playlist::RegionLock rl (this, false);
Glib::Threads::RecMutex::Lock rm (region_lock);
#else
Glib::RecMutex::Lock rm (region_lock);
#endif
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("++++++ %1 .. %2 +++++++ %3 trackers +++++++++++++++++\n", DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("++++++ %1 .. %2 +++++++ %3 trackers +++++++++++++++++\n",
start, start + dur, _note_trackers.size())); start, start + dur, _note_trackers.size()));
@ -298,11 +295,8 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec
void void
MidiPlaylist::clear_note_trackers () MidiPlaylist::clear_note_trackers ()
{ {
#ifdef HAVE_GLIB_THREADS_RECMUTEX Playlist::RegionLock rl (this, false);
Glib::Threads::RecMutex::Lock rm (region_lock);
#else
Glib::RecMutex::Lock rm (region_lock);
#endif
for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) { for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
delete n->second; delete n->second;
} }
@ -407,12 +401,7 @@ MidiPlaylist::contained_automation()
its OK to block (for short intervals). its OK to block (for short intervals).
*/ */
#ifdef HAVE_GLIB_THREADS_RECMUTEX Playlist::RegionLock rl (this, false);
Glib::Threads::RecMutex::Lock rm (region_lock);
#else
Glib::RecMutex::Lock rm (region_lock);
#endif
set<Evoral::Parameter> ret; set<Evoral::Parameter> ret;
for (RegionList::const_iterator r = regions.begin(); r != regions.end(); ++r) { for (RegionList::const_iterator r = regions.begin(); r != regions.end(); ++r) {

View File

@ -1758,6 +1758,12 @@ boost::shared_ptr<RegionList>
Playlist::regions_touched (framepos_t start, framepos_t end) Playlist::regions_touched (framepos_t start, framepos_t end)
{ {
RegionLock rlock (this); RegionLock rlock (this);
return regions_touched_locked (start, end);
}
boost::shared_ptr<RegionList>
Playlist::regions_touched_locked (framepos_t start, framepos_t end)
{
boost::shared_ptr<RegionList> rlist (new RegionList); boost::shared_ptr<RegionList> rlist (new RegionList);
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
@ -1769,126 +1775,125 @@ Playlist::regions_touched (framepos_t start, framepos_t end)
return rlist; return rlist;
} }
framepos_t framepos_t
Playlist::find_next_transient (framepos_t from, int dir) Playlist::find_next_transient (framepos_t from, int dir)
{ {
RegionLock rlock (this); RegionLock rlock (this);
AnalysisFeatureList points; AnalysisFeatureList points;
AnalysisFeatureList these_points; AnalysisFeatureList these_points;
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if (dir > 0) {
if ((*i)->last_frame() < from) {
continue;
}
} else {
if ((*i)->first_frame() > from) {
continue;
}
}
(*i)->get_transients (these_points);
/* add first frame, just, err, because */
these_points.push_back ((*i)->first_frame());
points.insert (points.end(), these_points.begin(), these_points.end());
these_points.clear ();
}
if (points.empty()) {
return -1;
}
TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
bool reached = false;
if (dir > 0) {
for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
if ((*x) >= from) {
reached = true;
}
if (reached && (*x) > from) {
return *x;
}
}
} else {
for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
if ((*x) <= from) {
reached = true;
}
if (reached && (*x) < from) {
return *x;
}
}
}
return -1;
}
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { boost::shared_ptr<Region>
if (dir > 0) { Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
if ((*i)->last_frame() < from) { {
continue; RegionLock rlock (this);
} boost::shared_ptr<Region> ret;
} else { framepos_t closest = max_framepos;
if ((*i)->first_frame() > from) {
continue; bool end_iter = false;
}
} for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
(*i)->get_transients (these_points); if(end_iter) break;
/* add first frame, just, err, because */ frameoffset_t distance;
boost::shared_ptr<Region> r = (*i);
these_points.push_back ((*i)->first_frame()); framepos_t pos = 0;
points.insert (points.end(), these_points.begin(), these_points.end()); switch (point) {
these_points.clear (); case Start:
} pos = r->first_frame ();
break;
if (points.empty()) { case End:
return -1; pos = r->last_frame ();
} break;
case SyncPoint:
TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0); pos = r->sync_position ();
bool reached = false; break;
}
if (dir > 0) {
for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) { switch (dir) {
if ((*x) >= from) { case 1: /* forwards */
reached = true;
} if (pos > frame) {
if ((distance = pos - frame) < closest) {
if (reached && (*x) > from) { closest = distance;
return *x; ret = r;
} end_iter = true;
} }
} else { }
for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
if ((*x) <= from) { break;
reached = true;
} default: /* backwards */
if (reached && (*x) < from) { if (pos < frame) {
return *x; if ((distance = frame - pos) < closest) {
} closest = distance;
} ret = r;
} }
} else {
return -1; end_iter = true;
} }
boost::shared_ptr<Region> break;
Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir) }
{ }
RegionLock rlock (this);
boost::shared_ptr<Region> ret; return ret;
framepos_t closest = max_framepos; }
bool end_iter = false;
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if(end_iter) break;
frameoffset_t distance;
boost::shared_ptr<Region> r = (*i);
framepos_t pos = 0;
switch (point) {
case Start:
pos = r->first_frame ();
break;
case End:
pos = r->last_frame ();
break;
case SyncPoint:
pos = r->sync_position ();
break;
}
switch (dir) {
case 1: /* forwards */
if (pos > frame) {
if ((distance = pos - frame) < closest) {
closest = distance;
ret = r;
end_iter = true;
}
}
break;
default: /* backwards */
if (pos < frame) {
if ((distance = frame - pos) < closest) {
closest = distance;
ret = r;
}
}
else {
end_iter = true;
}
break;
}
}
return ret;
}
framepos_t framepos_t
Playlist::find_next_region_boundary (framepos_t frame, int dir) Playlist::find_next_region_boundary (framepos_t frame, int dir)