From 0f11f0c25465464b28db713cccd37d7d8de483e1 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 9 May 2023 01:33:45 +0200 Subject: [PATCH] Allow signals to be blocked and resumed, and so make sure that a set of content changes taken from an examiner are handled at the same time. Should fix DoM #2523. --- src/lib/change_signaller.cc | 24 +++++++++ src/lib/change_signaller.h | 102 +++++++++++++++++++++++++++++++----- src/lib/content.h | 3 +- src/lib/dcp_content.cc | 8 ++- src/lib/film.h | 2 +- src/lib/wscript | 1 + 6 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 src/lib/change_signaller.cc diff --git a/src/lib/change_signaller.cc b/src/lib/change_signaller.cc new file mode 100644 index 000000000..a1f093d14 --- /dev/null +++ b/src/lib/change_signaller.cc @@ -0,0 +1,24 @@ +/* + Copyright (C) 2018-2021 Carl Hetherington + + 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 . + +*/ + + +#include "change_signaller.h" + + diff --git a/src/lib/change_signaller.h b/src/lib/change_signaller.h index 8612cf426..1d7d482df 100644 --- a/src/lib/change_signaller.h +++ b/src/lib/change_signaller.h @@ -23,6 +23,10 @@ #define DCPOMATIC_CHANGE_SIGNALLER_H +#include +#include + + enum class ChangeType { PENDING, @@ -31,30 +35,104 @@ enum class ChangeType }; +template +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 ChangeSignalDespatcher : public ChangeSignalDespatcherBase +{ +public: + ChangeSignalDespatcher() = default; + + ChangeSignalDespatcher(ChangeSignalDespatcher const&) = delete; + ChangeSignalDespatcher& operator=(ChangeSignalDespatcher const&) = delete; + + void signal_change(ChangeSignal 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* _instance; + if (!_instance) { + _instance = new ChangeSignalDespatcher(); + } + return _instance; + } + +private: + std::vector> _pending; + bool _suspended = false; + boost::mutex _mutex; +}; + + template 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::instance()->signal_change({_thing, _property, ChangeType::PENDING}); } ~ChangeSignaller () { - if (_done) { - _thing->signal_change (ChangeType::DONE, _property); - } else { - _thing->signal_change (ChangeType::CANCELLED, _property); - } + ChangeSignalDespatcher::instance()->signal_change({_thing, _property, _done ? ChangeType::DONE : ChangeType::CANCELLED}); } - ChangeSignaller (ChangeSignaller const&) = delete; - ChangeSignaller& operator= (ChangeSignaller const&) = delete; - void abort () { _done = false; diff --git a/src/lib/content.h b/src/lib/content.h index 0ce87ed9b..f2fecddf0 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -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 friend class ChangeSignaller; + template friend class ChangeSignalDespatcher; void signal_change (ChangeType, int); @@ -256,6 +256,7 @@ private: typedef ChangeSignaller ContentChangeSignaller; +typedef ChangeSignalDespatcher ContentChangeSignalDespatcher; #endif diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index 231a93bd0..cad775b24 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2022 Carl Hetherington + Copyright (C) 2014-2023 Carl Hetherington 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 @@ -213,6 +214,11 @@ DCPContent::examine (shared_ptr film, shared_ptr 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); diff --git a/src/lib/film.h b/src/lib/film.h index b7a9f94ac..958c388b3 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -492,7 +492,7 @@ private: friend struct ::isdcf_name_with_atmos; friend struct ::recover_test_2d_encrypted; friend struct ::atmos_encrypted_passthrough_test; - template friend class ChangeSignaller; + template friend class ChangeSignalDespatcher; boost::filesystem::path info_file (dcpomatic::DCPTimePeriod p) const; diff --git a/src/lib/wscript b/src/lib/wscript index f8c2d5dc2..de7b947c2 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -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 -- 2.30.2