Allow signals to be blocked and resumed, and so make sure that a set
authorCarl Hetherington <cth@carlh.net>
Mon, 8 May 2023 23:33:45 +0000 (01:33 +0200)
committerCarl Hetherington <cth@carlh.net>
Wed, 10 May 2023 19:35:46 +0000 (21:35 +0200)
of content changes taken from an examiner are handled at the same
time.

Should fix DoM #2523.

src/lib/change_signaller.cc [new file with mode: 0644]
src/lib/change_signaller.h
src/lib/content.h
src/lib/dcp_content.cc
src/lib/film.h
src/lib/wscript

diff --git a/src/lib/change_signaller.cc b/src/lib/change_signaller.cc
new file mode 100644 (file)
index 0000000..a1f093d
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+    Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "change_signaller.h"
+
+
index 8612cf42672b2c8ca42ae270bb896925a6cd20d4..1d7d482df2539d8c989609e4cf162a323ceb7bfd 100644 (file)
 #define DCPOMATIC_CHANGE_SIGNALLER_H
 
 
+#include <boost/thread.hpp>
+#include <vector>
+
+
 enum class ChangeType
 {
        PENDING,
@@ -31,30 +35,104 @@ enum class ChangeType
 };
 
 
+template <class T, class P>
+class ChangeSignal
+{
+public:
+       ChangeSignal(T* thing_, P property_, ChangeType type_)
+               : thing(thing_)
+               , property(property_)
+               , type(type_)
+       {}
+
+       T* thing;
+       P property;
+       ChangeType type;
+};
+
+
+class ChangeSignalDespatcherBase
+{
+protected:
+       static boost::mutex _instance_mutex;
+};
+
+
+template <class T, class P>
+class ChangeSignalDespatcher : public ChangeSignalDespatcherBase
+{
+public:
+       ChangeSignalDespatcher() = default;
+
+       ChangeSignalDespatcher(ChangeSignalDespatcher const&) = delete;
+       ChangeSignalDespatcher& operator=(ChangeSignalDespatcher const&) = delete;
+
+       void signal_change(ChangeSignal<T, P> const& signal)
+       {
+               if (_suspended) {
+                       boost::mutex::scoped_lock lm(_mutex);
+                       _pending.push_back(signal);
+               } else {
+                       signal.thing->signal_change(signal.type, signal.property);
+               }
+       }
+
+       void suspend()
+       {
+               boost::mutex::scoped_lock lm(_mutex);
+               _suspended = true;
+       }
+
+       void resume()
+       {
+               boost::mutex::scoped_lock lm(_mutex);
+               auto pending = _pending;
+               lm.unlock();
+
+               for (auto signal: pending) {
+                       signal.thing->signal_change(signal.type, signal.property);
+               }
+
+               lm.lock();
+               _pending.clear();
+               _suspended = false;
+       }
+
+       static ChangeSignalDespatcher* instance()
+       {
+               static boost::mutex _instance_mutex;
+               static boost::mutex::scoped_lock lm(_instance_mutex);
+               static ChangeSignalDespatcher<T, P>* _instance;
+               if (!_instance) {
+                       _instance = new ChangeSignalDespatcher<T, P>();
+               }
+               return _instance;
+       }
+
+private:
+       std::vector<ChangeSignal<T, P>> _pending;
+       bool _suspended = false;
+       boost::mutex _mutex;
+};
+
+
 template <class T, class P>
 class ChangeSignaller
 {
 public:
        ChangeSignaller (T* t, P p)
-               : _thing (t)
-               , _property (p)
-               , _done (true)
+               : _thing(t)
+               , _property(p)
+               , _done(true)
        {
-               _thing->signal_change (ChangeType::PENDING, _property);
+               ChangeSignalDespatcher<T, P>::instance()->signal_change({_thing, _property, ChangeType::PENDING});
        }
 
        ~ChangeSignaller ()
        {
-               if (_done) {
-                       _thing->signal_change (ChangeType::DONE, _property);
-               } else {
-                       _thing->signal_change (ChangeType::CANCELLED, _property);
-               }
+               ChangeSignalDespatcher<T, P>::instance()->signal_change({_thing, _property, _done ? ChangeType::DONE : ChangeType::CANCELLED});
        }
 
-       ChangeSignaller (ChangeSignaller const&) = delete;
-       ChangeSignaller& operator= (ChangeSignaller const&) = delete;
-
        void abort ()
        {
                _done = false;
index 0ce87ed9be0a192ec6923036f724b9d33abe7cd0..f2fecddf063df96a2546fffb66cd82722922aa13 100644 (file)
@@ -234,7 +234,7 @@ private:
        friend struct best_dcp_frame_rate_test_double;
        friend struct audio_sampling_rate_test;
        friend struct subtitle_font_id_change_test2;
-       template<class, class> friend class ChangeSignaller;
+       template<class, class> friend class ChangeSignalDespatcher;
 
        void signal_change (ChangeType, int);
 
@@ -256,6 +256,7 @@ private:
 
 
 typedef ChangeSignaller<Content, int> ContentChangeSignaller;
+typedef ChangeSignalDespatcher<Content, int> ContentChangeSignalDespatcher;
 
 
 #endif
index 231a93bd0bec27c37574b785428ca792a185ffbb..cad775b24854b9c79aba7448570c11a70edd99ce 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2022 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2023 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -31,6 +31,7 @@
 #include "job.h"
 #include "log.h"
 #include "overlaps.h"
+#include "scope_guard.h"
 #include "text_content.h"
 #include "video_content.h"
 #include <dcp/dcp.h>
@@ -213,6 +214,11 @@ DCPContent::examine (shared_ptr<const Film> film, shared_ptr<Job> job)
        bool const needed_kdm = needs_kdm ();
        string const old_name = name ();
 
+       ContentChangeSignalDespatcher::instance()->suspend();
+       ScopeGuard sg = []() {
+               ContentChangeSignalDespatcher::instance()->resume();
+       };
+
        ContentChangeSignaller cc_texts (this, DCPContentProperty::TEXTS);
        ContentChangeSignaller cc_assets (this, DCPContentProperty::NEEDS_ASSETS);
        ContentChangeSignaller cc_kdm (this, DCPContentProperty::NEEDS_KDM);
index b7a9f94ace3a03c62ab69102684672703aae1135..958c388b3a7a8d21c3f679dfa8ce006c6791e707 100644 (file)
@@ -492,7 +492,7 @@ private:
        friend struct ::isdcf_name_with_atmos;
        friend struct ::recover_test_2d_encrypted;
        friend struct ::atmos_encrypted_passthrough_test;
-       template <class, class> friend class ChangeSignaller;
+       template <class, class> friend class ChangeSignalDespatcher;
 
        boost::filesystem::path info_file (dcpomatic::DCPTimePeriod p) const;
 
index f8c2d5dc264d190fbcb8a1496db2cd8f2089a6ce..de7b947c22e5c202f44797accf563b5aa3b8c7a0 100644 (file)
@@ -51,6 +51,7 @@ sources = """
           check_content_job.cc
           cinema.cc
           cinema_sound_processor.cc
+          change_signaller.cc
           collator.cc
           colour_conversion.cc
           config.cc