fix (?) tricky locking issues in the tempo map by adding a second lock and independen...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 4 Jan 2012 17:55:42 +0000 (17:55 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 4 Jan 2012 17:55:42 +0000 (17:55 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@11157 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/tempo.h
libs/ardour/tempo.cc

index 3f4b783de762e0b45ca3fc6ba0b895699fdcccf7..f0a63be05ffa22ed624ddf18c05e3b846e671dfa 100644 (file)
@@ -223,16 +223,14 @@ class TempoMap : public PBD::StatefulDestructible
        typedef std::vector<BBTPoint> BBTPointList;
 
        template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
-               Glib::RWLock::ReaderLock lm (lock);
+               Glib::RWLock::ReaderLock lm (metrics_lock);
                (obj.*method)(*metrics);
        }
 
-       const BBTPointList& map() const { return _map ; }
-
        void map (BBTPointList::const_iterator&, BBTPointList::const_iterator&, 
                  framepos_t start, framepos_t end);
        
-       void      bbt_time (framepos_t when, Timecode::BBT_Time&);
+       void       bbt_time (framepos_t when, Timecode::BBT_Time&);
         framecnt_t frame_time (const Timecode::BBT_Time&);
        framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
 
@@ -299,31 +297,32 @@ class TempoMap : public PBD::StatefulDestructible
        framepos_t           last_bbt_when;
        bool                 last_bbt_valid;
        Timecode::BBT_Time   last_bbt;
-       mutable Glib::RWLock lock;
-       BBTPointList          _map;
+       mutable Glib::RWLock metrics_lock;
+       mutable Glib::RWLock map_lock;
+       BBTPointList*       _map;
 
        void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
         void require_map_to (framepos_t pos);
         void require_map_to (const Timecode::BBT_Time&);
 
-    BBTPointList::const_iterator bbt_before_or_at (framepos_t);
-    BBTPointList::const_iterator bbt_after_or_at (framepos_t);
-    BBTPointList::const_iterator bbt_point_for (const Timecode::BBT_Time&);
-
+       BBTPointList::const_iterator bbt_before_or_at (framepos_t);
+       BBTPointList::const_iterator bbt_after_or_at (framepos_t);
+       BBTPointList::const_iterator bbt_point_for (const Timecode::BBT_Time&);
+       
        void timestamp_metrics_from_audio_time ();
-
+       
        framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
-
+       
         void bbt_time_unlocked (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&);
-
-    framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
-
+       
+       framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
+       
        const MeterSection& first_meter() const;
        const TempoSection& first_tempo() const;
-
+       
        int move_metric_section (MetricSection&, const Timecode::BBT_Time& to);
        void do_insert (MetricSection* section);
-
+       
        Timecode::BBT_Time bbt_add (const Timecode::BBT_Time&, const Timecode::BBT_Time&, const TempoMetric&) const;
        Timecode::BBT_Time bbt_add (const Timecode::BBT_Time& a, const Timecode::BBT_Time& b) const;
        Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
index 54bb23d51743613e2faf21469a8334c995f38176..e8f894c1b4ea4ef5feeef795e067524c78a482bc 100644 (file)
@@ -278,6 +278,7 @@ struct MetricSectionSorter {
 TempoMap::TempoMap (framecnt_t fr)
 {
        metrics = new Metrics;
+       _map = new BBTPointList;
        _frame_rate = fr;
        last_bbt_valid = false;
        BBT_Time start;
@@ -300,6 +301,8 @@ TempoMap::TempoMap (framecnt_t fr)
 
 TempoMap::~TempoMap ()
 {
+       delete metrics;
+       delete _map;
 }
 
 void
@@ -308,7 +311,7 @@ TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
        bool removed = false;
 
        {
-               Glib::RWLock::WriterLock lm (lock);
+               Glib::RWLock::WriterLock lm (metrics_lock);
                Metrics::iterator i;
 
                for (i = metrics->begin(); i != metrics->end(); ++i) {
@@ -322,13 +325,10 @@ TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
                                }
                        }
                }
-
-               if (removed && complete_operation) {
-                       recompute_map (false);
-               }
        }
 
        if (removed && complete_operation) {
+               recompute_map (false);
                PropertyChanged (PropertyChange ());
        }
 }
@@ -339,7 +339,7 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
        bool removed = false;
 
        {
-               Glib::RWLock::WriterLock lm (lock);
+               Glib::RWLock::WriterLock lm (metrics_lock);
                Metrics::iterator i;
 
                for (i = metrics->begin(); i != metrics->end(); ++i) {
@@ -353,15 +353,10 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
                                }
                        }
                }
-               
-               if (removed && complete_operation) {
-                       recompute_map (true);
-               }
-
-
        }
 
        if (removed && complete_operation) {
+               recompute_map (true);
                PropertyChanged (PropertyChange ());
        }
 }
@@ -369,9 +364,6 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
 void
 TempoMap::do_insert (MetricSection* section)
 {
-       /* CALLER MUST HOLD WRITE LOCK */
-
-       bool reassign_tempo_bbt = false;
        bool need_add = true;
 
        assert (section->start().ticks == 0);
@@ -386,8 +378,6 @@ TempoMap::do_insert (MetricSection* section)
                   sections based on this new meter.
                */
                
-               reassign_tempo_bbt = true;
-
                if ((section->start().beats != 1) || (section->start().ticks != 0)) {
                        
                        BBT_Time corrected = section->start();
@@ -469,8 +459,6 @@ TempoMap::do_insert (MetricSection* section)
                        metrics->insert (metrics->end(), section);
                }
        }
-
-       recompute_map (reassign_tempo_bbt);
 }
 
 void
@@ -482,9 +470,12 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T
                remove_tempo (ts, false);
                add_tempo (tempo, where);
        } else {
-               Glib::RWLock::WriterLock lm (lock);
-               /* cannot move the first tempo section */
-               *((Tempo*)&first) = tempo;
+               {
+                       Glib::RWLock::WriterLock lm (metrics_lock);
+                       /* cannot move the first tempo section */
+                       *((Tempo*)&first) = tempo;
+               }
+
                recompute_map (false);
        }
 
@@ -495,7 +486,7 @@ void
 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
 {
        {
-               Glib::RWLock::WriterLock lm (lock);
+               Glib::RWLock::WriterLock lm (metrics_lock);
 
                /* new tempos always start on a beat */
                where.ticks = 0;
@@ -531,10 +522,12 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
                ts->update_bar_offset_from_bbt (*meter);
 
                /* and insert it */
-
+               
                do_insert (ts);
        }
 
+       recompute_map (false);
+
        PropertyChanged (PropertyChange ());
 }
 
@@ -547,9 +540,11 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
                remove_meter (ms, false);
                add_meter (meter, where);
        } else {
-               Glib::RWLock::WriterLock lm (lock);
-               /* cannot move the first meter section */
-               *((Meter*)&first) = meter;
+               {
+                       Glib::RWLock::WriterLock lm (metrics_lock);
+                       /* cannot move the first meter section */
+                       *((Meter*)&first) = meter;
+               }
                recompute_map (true);
        }
 
@@ -560,7 +555,7 @@ void
 TempoMap::add_meter (const Meter& meter, BBT_Time where)
 {
        {
-               Glib::RWLock::WriterLock lm (lock);
+               Glib::RWLock::WriterLock lm (metrics_lock);
 
                /* a new meter always starts a new bar on the first beat. so
                   round the start time appropriately. remember that
@@ -576,10 +571,12 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where)
 
                /* new meters *always* start on a beat. */
                where.ticks = 0;
-
+               
                do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
        }
 
+       recompute_map (true);
+       
 #ifndef NDEBUG
        if (DEBUG_ENABLED(DEBUG::TempoMap)) {
                dump (std::cerr);
@@ -598,10 +595,10 @@ TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
        for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
                if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
                        {
-                               Glib::RWLock::WriterLock lm (lock);
+                               Glib::RWLock::WriterLock lm (metrics_lock);
                                *((Tempo*) t) = newtempo;
-                               recompute_map (false);
                        }
+                       recompute_map (false);
                        PropertyChanged (PropertyChange ());
                        break;
                }
@@ -648,12 +645,12 @@ TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, d
        /* reset */
 
        {
-               Glib::RWLock::WriterLock lm (lock);
+               Glib::RWLock::WriterLock lm (metrics_lock);
                /* cannot move the first tempo section */
                *((Tempo*)prev) = newtempo;
-               recompute_map (false);
        }
 
+       recompute_map (false);
        PropertyChanged (PropertyChange ());
 }
 
@@ -774,7 +771,14 @@ TempoMap::timestamp_metrics_from_audio_time ()
 void
 TempoMap::require_map_to (framepos_t pos)
 {
-       if (_map.empty() || _map.back().frame < pos) {
+       bool revise_map;
+
+       {
+               Glib::RWLock::ReaderLock lm (map_lock);
+               revise_map = (_map->empty() || _map->back().frame < pos);
+       }
+
+       if (revise_map) {
                recompute_map (false, pos);
        }
 }
@@ -782,7 +786,14 @@ TempoMap::require_map_to (framepos_t pos)
 void
 TempoMap::require_map_to (const BBT_Time& bbt)
 {
-       if (_map.empty() || _map.back().bbt() < bbt) {
+       bool revise_map;
+
+       {
+               Glib::RWLock::ReaderLock lm (map_lock);
+               revise_map = (_map->empty() || _map->back().bbt() < bbt);
+       }
+
+       if (revise_map) {
                recompute_map (false, 99);
        }
 }
@@ -799,20 +810,24 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
        double current_frame;
        BBT_Time current;
        Metrics::iterator next_metric;
+       BBTPointList* new_map = new BBTPointList;
 
        if (end < 0) {
-               if (_map.empty()) {
+
+               Glib::RWLock::ReaderLock lm (map_lock);
+
+               if (_map->empty()) {
                        /* compute 1 mins worth */
                        end = _frame_rate * 60;
                } else {
-                       end = _map.back().frame;
+                       end = _map->back().frame;
                }
        }
 
        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
-       
-       _map.clear ();
 
+       Glib::RWLock::ReaderLock lm (metrics_lock);
+       
        for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
                if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
                        meter = ms;
@@ -873,7 +888,7 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
        ++next_metric; // skip tempo (or meter)
 
        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
-       _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), 1, 1));
+       new_map->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), 1, 1));
 
        while (current_frame < end) {
                
@@ -973,18 +988,24 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
 
                if (current.beats == 1) {
                        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
-                       _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
+                       new_map->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
                } else {
                        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
-                       _map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
+                       new_map->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
                }
        }
+
+       {
+               Glib::RWLock::WriterLock lm (map_lock);
+               swap (_map, new_map);
+               delete new_map;
+       }
 }
 
 TempoMetric
 TempoMap::metric_at (framepos_t frame) const
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (metrics_lock);
        TempoMetric m (first_meter(), first_tempo());
        const Meter* meter;
        const Tempo* tempo;
@@ -1021,7 +1042,7 @@ TempoMap::metric_at (framepos_t frame) const
 TempoMetric
 TempoMap::metric_at (BBT_Time bbt) const
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (metrics_lock);
        TempoMetric m (first_meter(), first_tempo());
        const Meter* meter;
        const Tempo* tempo;
@@ -1058,7 +1079,7 @@ void
 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
 {
        {
-               Glib::RWLock::ReaderLock lm (lock);
+               Glib::RWLock::ReaderLock lm (map_lock);
                BBTPointList::const_iterator i = bbt_before_or_at (frame);
                bbt_time_unlocked (frame, bbt, i);
        }
@@ -1081,7 +1102,7 @@ TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt, const BBTPointList
 framepos_t
 TempoMap::frame_time (const BBT_Time& bbt)
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (map_lock);
 
        BBTPointList::const_iterator s = bbt_point_for (BBT_Time (1, 1, 0));
        BBTPointList::const_iterator e = bbt_point_for (BBT_Time (bbt.bars, bbt.beats, 0));
@@ -1097,7 +1118,7 @@ TempoMap::frame_time (const BBT_Time& bbt)
 framecnt_t
 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (map_lock);
        framecnt_t frames = 0;
        BBT_Time when;
 
@@ -1119,7 +1140,7 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
        BBTPointList::const_iterator start (wi);
        double tick_frames = 0;
 
-       assert (wi != _map.end());
+       assert (wi != _map->end());
 
        /* compute how much rounding we did because of non-zero ticks */
 
@@ -1130,19 +1151,19 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
        uint32_t bars = 0;
        uint32_t beats = 0;
 
-       while (wi != _map.end() && bars < bbt.bars) {
+       while (wi != _map->end() && bars < bbt.bars) {
                ++wi;
                if ((*wi).is_bar()) {
                        ++bars;
                }
        }
-       assert (wi != _map.end());
+       assert (wi != _map->end());
 
-       while (wi != _map.end() && beats < bbt.beats) {
+       while (wi != _map->end() && beats < bbt.beats) {
                ++wi;
                ++beats;
        }
-       assert (wi != _map.end());
+       assert (wi != _map->end());
 
        /* add any additional frames related to ticks in the added value */
 
@@ -1156,25 +1177,19 @@ TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, i
 framepos_t
 TempoMap::round_to_bar (framepos_t fr, int dir)
 {
-       {
-               Glib::RWLock::ReaderLock lm (lock);
-               return round_to_type (fr, dir, Bar);
-       }
+       return round_to_type (fr, dir, Bar);
 }
 
 framepos_t
 TempoMap::round_to_beat (framepos_t fr, int dir)
 {
-       {
-               Glib::RWLock::ReaderLock lm (lock);
-               return round_to_type (fr, dir, Beat);
-       }
+       return round_to_type (fr, dir, Beat);
 }
 
 framepos_t
 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (map_lock);
        BBTPointList::const_iterator i = bbt_before_or_at (fr);
        BBT_Time the_beat;
        uint32_t ticks_one_subdivisions_worth;
@@ -1204,9 +1219,9 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
                }
 
                if (the_beat.ticks > BBT_Time::ticks_per_bar_division) {
-                       assert (i != _map.end());
+                       assert (i != _map->end());
                        ++i;
-                       assert (i != _map.end());
+                       assert (i != _map->end());
                        the_beat.ticks -= BBT_Time::ticks_per_bar_division;
                } 
 
@@ -1229,7 +1244,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
                }
 
                if (the_beat.ticks < difference) {
-                       if (i == _map.begin()) {
+                       if (i == _map->begin()) {
                                /* can't go backwards from wherever pos is, so just return it */
                                return fr;
                        }
@@ -1255,9 +1270,9 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
                        DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", the_beat.ticks));
 
                        if (the_beat.ticks > BBT_Time::ticks_per_bar_division) {
-                               assert (i != _map.end());
+                               assert (i != _map->end());
                                ++i;
-                               assert (i != _map.end());
+                               assert (i != _map->end());
                                the_beat.ticks -= BBT_Time::ticks_per_bar_division;
                                DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", the_beat));
                        } 
@@ -1267,7 +1282,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
                        /* closer to previous subdivision, so shift backward */
 
                        if (rem > the_beat.ticks) {
-                               if (i == _map.begin()) {
+                               if (i == _map->begin()) {
                                        /* can't go backwards past zero, so ... */
                                        return 0;
                                }
@@ -1291,6 +1306,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
 framepos_t
 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
 {
+       Glib::RWLock::ReaderLock lm (map_lock);
        BBTPointList::const_iterator fi;
 
        if (dir > 0) {
@@ -1299,7 +1315,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
                fi = bbt_before_or_at (frame);
        }
 
-       assert (fi != _map.end());
+       assert (fi != _map->end());
 
        DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3|%4 @ %5) to bars in direction %2\n", frame, dir, (*fi).bar, (*fi).beat, (*fi).frame));
                
@@ -1313,7 +1329,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
                        }
 
                        while (!(*fi).is_bar()) {
-                               if (fi == _map.begin()) {
+                               if (fi == _map->begin()) {
                                        break;
                                }
                                fi--;
@@ -1332,7 +1348,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
 
                        while (!(*fi).is_bar()) {
                                fi++;
-                               if (fi == _map.end()) {
+                               if (fi == _map->end()) {
                                        --fi;
                                        break;
                                }
@@ -1354,7 +1370,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
                        }
 
                        while ((*prev).beat != 1) {
-                               if (prev == _map.begin()) {
+                               if (prev == _map->begin()) {
                                        break;
                                }
                                prev--;
@@ -1362,7 +1378,7 @@ TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
 
                        while ((*next).beat != 1) {
                                next++;
-                               if (next == _map.end()) {
+                               if (next == _map->end()) {
                                        --next;
                                        break;
                                }
@@ -1425,18 +1441,15 @@ TempoMap::map (TempoMap::BBTPointList::const_iterator& begin,
               TempoMap::BBTPointList::const_iterator& end, 
               framepos_t lower, framepos_t upper) 
 {
-       if (_map.empty() || upper >= _map.back().frame) {
-               recompute_map (false, upper);
-       }
-
-       begin = lower_bound (_map.begin(), _map.end(), lower);
-       end = upper_bound (_map.begin(), _map.end(), upper);
+       require_map_to (upper);
+       begin = lower_bound (_map->begin(), _map->end(), lower);
+       end = upper_bound (_map->begin(), _map->end(), upper);
 }
 
 const TempoSection&
 TempoMap::tempo_section_at (framepos_t frame) const
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (metrics_lock);
        Metrics::const_iterator i;
        TempoSection* prev = 0;
 
@@ -1482,7 +1495,7 @@ TempoMap::get_state ()
        XMLNode *root = new XMLNode ("TempoMap");
 
        {
-               Glib::RWLock::ReaderLock lm (lock);
+               Glib::RWLock::ReaderLock lm (metrics_lock);
                for (i = metrics->begin(); i != metrics->end(); ++i) {
                        root->add_child_nocopy ((*i)->get_state());
                }
@@ -1495,7 +1508,7 @@ int
 TempoMap::set_state (const XMLNode& node, int /*version*/)
 {
        {
-               Glib::RWLock::WriterLock lm (lock);
+               Glib::RWLock::WriterLock lm (metrics_lock);
 
                XMLNodeList nlist;
                XMLNodeConstIterator niter;
@@ -1545,13 +1558,12 @@ TempoMap::set_state (const XMLNode& node, int /*version*/)
                }
 
                if (niter == nlist.end()) {
-
                        MetricSectionSorter cmp;
                        metrics->sort (cmp);
-                       recompute_map (true);
                }
        }
 
+       recompute_map (true);
        PropertyChanged (PropertyChange ());
 
        return 0;
@@ -1560,6 +1572,7 @@ TempoMap::set_state (const XMLNode& node, int /*version*/)
 void
 TempoMap::dump (std::ostream& o) const
 {
+       Glib::RWLock::ReaderLock lm (metrics_lock);
        const MeterSection* m;
        const TempoSection* t;
 
@@ -1578,7 +1591,7 @@ TempoMap::dump (std::ostream& o) const
 int
 TempoMap::n_tempos() const
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (metrics_lock);
        int cnt = 0;
 
        for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
@@ -1593,7 +1606,7 @@ TempoMap::n_tempos() const
 int
 TempoMap::n_meters() const
 {
-       Glib::RWLock::ReaderLock lm (lock);
+       Glib::RWLock::ReaderLock lm (metrics_lock);
        int cnt = 0;
 
        for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
@@ -1608,6 +1621,7 @@ TempoMap::n_meters() const
 void
 TempoMap::insert_time (framepos_t where, framecnt_t amount)
 {
+       Glib::RWLock::WriterLock lm (metrics_lock);
        for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
                if ((*i)->frame() >= where && (*i)->movable ()) {
                        (*i)->set_frame ((*i)->frame() + amount);
@@ -1638,6 +1652,7 @@ TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats)
 framepos_t
 TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op)
 {
+       Glib::RWLock::ReaderLock lm (map_lock);
        BBTPointList::const_iterator i;
        framecnt_t extra_frames = 0;
 
@@ -1650,7 +1665,7 @@ TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op)
        
        /* walk backwards */
 
-       while (i != _map.begin() && (op.bars || op.beats)) {
+       while (i != _map->begin() && (op.bars || op.beats)) {
                --i;
                if ((*i).is_bar()) {
                        if (op.bars) {
@@ -1683,6 +1698,7 @@ TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op)
 framepos_t
 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
 {
+       Glib::RWLock::ReaderLock lm (map_lock);
        BBT_Time op_copy (op);
        int additional_minutes = 1;
        BBTPointList::const_iterator i;
@@ -1697,7 +1713,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
                /* we know that (*i).frame is before or equal to pos */
                backup_frames = pos - (*i).frame;
 
-               while (i != _map.end() && (op.bars || op.beats)) {
+               while (i != _map->end() && (op.bars || op.beats)) {
                        ++i;
                        if ((*i).is_bar()) {
                                if (op.bars) {
@@ -1710,7 +1726,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
                        }
                }
                
-               if (i != _map.end()) {
+               if (i != _map->end()) {
                        break;
                }
 
@@ -1722,7 +1738,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
 
                /* go back and try again */
                warning << "reached end of map with op now at " << op << " end = " 
-                       << _map.back().frame << ' ' << _map.back().bar << '|' << _map.back().beat << ", trying to walk " 
+                       << _map->back().frame << ' ' << _map->back().bar << '|' << _map->back().beat << ", trying to walk " 
                        << op_copy << " ... retry" 
                        << endmsg;
        }
@@ -1741,6 +1757,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
 Evoral::MusicalTime
 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance)
 {
+       Glib::RWLock::ReaderLock lm (map_lock);
        BBTPointList::const_iterator i = bbt_after_or_at (pos);
        Evoral::MusicalTime beats = 0;
        framepos_t end = pos + distance;
@@ -1755,11 +1772,11 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance)
                beats += ((*i).frame - pos) / (*i).meter->frames_per_division (*(*i).tempo, _frame_rate);
        }
 
-       while (i != _map.end() && (*i).frame < end) {
+       while (i != _map->end() && (*i).frame < end) {
                ++i;
                beats++;
        }
-       assert (i != _map.end());
+       assert (i != _map->end());
        
        /* if our ending BBTPoint is after the end, subtract a fractional beat
           to represent that distance.
@@ -1775,12 +1792,17 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance)
 TempoMap::BBTPointList::const_iterator
 TempoMap::bbt_before_or_at (framepos_t pos)
 {
+       BBTPointList::const_iterator i;
+
        require_map_to (pos);
-       BBTPointList::const_iterator i = lower_bound (_map.begin(), _map.end(), pos);
-       assert (i != _map.end());
-       if ((*i).frame > pos) {
-               assert (i != _map.begin());
-               --i;
+       {
+               Glib::RWLock::ReaderLock lm (map_lock);
+               i = lower_bound (_map->begin(), _map->end(), pos);
+               assert (i != _map->end());
+               if ((*i).frame > pos) {
+                       assert (i != _map->begin());
+                       --i;
+               }
        }
        return i;
 }
@@ -1788,9 +1810,14 @@ TempoMap::bbt_before_or_at (framepos_t pos)
 TempoMap::BBTPointList::const_iterator
 TempoMap::bbt_after_or_at (framepos_t pos)
 {
+       BBTPointList::const_iterator i;
+
        require_map_to (pos);
-       BBTPointList::const_iterator i = upper_bound (_map.begin(), _map.end(), pos);
-       assert (i != _map.end());
+       {
+               Glib::RWLock::ReaderLock lm (map_lock);
+               i = upper_bound (_map->begin(), _map->end(), pos);
+               assert (i != _map->end());
+       }
        return i;
 }
 
@@ -1803,17 +1830,28 @@ struct bbtcmp {
 TempoMap::BBTPointList::const_iterator
 TempoMap::bbt_point_for (const BBT_Time& bbt)
 {
+       BBTPointList::const_iterator i;
        bbtcmp cmp;
        int additional_minutes = 1;
 
-       while (_map.empty() || _map.back().bar < (bbt.bars + 1)) {
+       while (1) {
+               {
+                       Glib::RWLock::ReaderLock lm (map_lock);
+                       if (!_map->empty() && _map->back().bar >= (bbt.bars + 1)) {
+                               break;
+                       }
+               }
                /* add some more distance, using bigger steps each time */
-               require_map_to (_map.back().frame + (_frame_rate * 60 * additional_minutes));
+               require_map_to (_map->back().frame + (_frame_rate * 60 * additional_minutes));
                additional_minutes *= 2;
        }
 
-       BBTPointList::const_iterator i = lower_bound (_map.begin(), _map.end(), bbt, cmp);
-       assert (i != _map.end());
+       {
+               Glib::RWLock::ReaderLock lm (map_lock);
+               i = lower_bound (_map->begin(), _map->end(), bbt, cmp);
+               assert (i != _map->end());
+       }
+
        return i;
 }