diff options
| author | Carl Hetherington <cth@carlh.net> | 2025-10-26 02:11:38 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-10-26 02:11:38 +0200 |
| commit | a645b0cff750bcd8c470055c227457d7d0d3e077 (patch) | |
| tree | 679be046c44281661ba424b63690009323d2265a /src | |
| parent | 60ab02524bc8d64a1c81e29e5e74c169bc87f76c (diff) | |
Add new signalling code.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/signal.cc | 17 | ||||
| -rw-r--r-- | src/lib/signal.h | 183 | ||||
| -rw-r--r-- | src/lib/wscript | 1 | ||||
| -rw-r--r-- | src/wx/wx_signal.h | 49 |
4 files changed, 250 insertions, 0 deletions
diff --git a/src/lib/signal.cc b/src/lib/signal.cc new file mode 100644 index 000000000..ba7f95685 --- /dev/null +++ b/src/lib/signal.cc @@ -0,0 +1,17 @@ + +#include "signal.h" + +boost::mutex pending::mutex; +std::map<boost::thread::id, std::list<std::function<void ()>>> pending::callbacks; + +ThreadWaker* thread_waker = nullptr; + +void pending::process() +{ + boost::mutex::scoped_lock lm(mutex); + auto const thread_id = boost::this_thread::get_id(); + for (auto i: callbacks[thread_id]) { + i(); + } + callbacks[thread_id].clear(); +} diff --git a/src/lib/signal.h b/src/lib/signal.h new file mode 100644 index 000000000..a2ea1cf98 --- /dev/null +++ b/src/lib/signal.h @@ -0,0 +1,183 @@ +/* + Copyright (C) 2025 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/>. + +*/ + + +#ifndef DCPOMATIC_SIGNAL_H +#define DCPOMATIC_SIGNAL_H + + +#include <boost/thread.hpp> +#include <iostream> + + +class SignalBase +{ +public: + virtual ~SignalBase() = default; + virtual void disconnect(int id) = 0; +}; + + +/** @class Connection + * @brief Record of a connection to a signal, so it can be disconnected. + */ +class Connection +{ +public: + Connection(SignalBase& signal, int id) + : _signal(signal) + , _id(id) + {} + + Connection& operator=(Connection const& other) + { + _signal = other._signal; + _id = other._id; + return *this; + } + + void disconnect() + { + _signal.disconnect(_id); + } + +private: + SignalBase& _signal; + int _id; +}; + + +/** @class ScopedConnection + * @brief Connection that disconnects itself on destruction. + */ +class ScopedConnection +{ +public: + ScopedConnection() {} + + ScopedConnection(Connection connection) + : _connection(std::move(connection)) + {} + + ScopedConnection(ScopedConnection const& other) = delete; + + ScopedConnection(ScopedConnection&& other) + : _connection(std::move(other._connection)) + {} + + ScopedConnection& operator=(ScopedConnection const& other) = delete; + + ScopedConnection& operator=(ScopedConnection&& other) + { + if (this != &other) { + _connection = other._connection; + other._connection.reset(); + } + return *this; + } + + ~ScopedConnection() + { + if (_connection) { + _connection->disconnect(); + } + } + +private: + boost::optional<Connection> _connection; +}; + + +namespace pending { + +extern boost::mutex mutex; +extern std::map<boost::thread::id, std::list<std::function<void ()>>> callbacks; +extern void process(); + +}; + + +class ThreadWaker +{ +public: + virtual void wake() {} +}; + + +extern ThreadWaker* thread_waker; + + +template <typename Parameters> +class Signal : public SignalBase +{ +private: + struct Callback + { + int id; + boost::thread::id thread; + std::function<Parameters> function; + }; + +public: + Connection connect(std::function<Parameters> callback) + { + boost::mutex::scoped_lock lm(_mutex); + auto const id = _id++; + auto const thread_id = boost::this_thread::get_id(); + _callbacks.push_back(Callback{id, thread_id, callback}); + return Connection(*this, id); + } + + void disconnect(int id) override + { + boost::mutex::scoped_lock lm(_mutex); + auto iter = std::find_if(_callbacks.begin(), _callbacks.end(), [id](Callback const& callback) { return callback.id == id; }); + if (iter != _callbacks.end()) { + _callbacks.erase(iter); + } + } + + template <typename... Args> + void emit(Args... args) + { + boost::mutex::scoped_lock lm(_mutex); + auto thread_id = boost::this_thread::get_id(); + for (auto const& callback: _callbacks) { + if (thread_id == callback.thread) { + callback.function(args...); + } else { + boost::mutex::scoped_lock lm2(pending::mutex); + pending::callbacks[callback.thread].push_back(boost::bind(callback.function, args...)); + if (thread_waker) { + thread_waker->wake(); + } + } + } + } + +private: + boost::mutex _mutex; + int _id = 0; + std::list<Callback> _callbacks; +}; + + +#endif + diff --git a/src/lib/wscript b/src/lib/wscript index 2e7b0339c..bc4c7d472 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -192,6 +192,7 @@ sources = """ send_notification_email_job.cc send_problem_report_job.cc server.cc + signal.cc shuffler.cc state.cc spl.cc diff --git a/src/wx/wx_signal.h b/src/wx/wx_signal.h new file mode 100644 index 000000000..e59592755 --- /dev/null +++ b/src/wx/wx_signal.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2016-2022 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 "lib/signal.h" +#include <dcp/warnings.h> +LIBDCP_DISABLE_WARNINGS +#include <wx/wx.h> +LIBDCP_ENABLE_WARNINGS + + +/** @class wxThreadWaker + * @brief Class to wake a thread so that it looks for incoming signals that it should deliver. + */ +class wxThreadWaker : public ThreadWaker +{ +public: + wxThreadWaker(wxEvtHandler* handler) + : _handler(handler) + {} + + void wake() override + { + /* This will result in an idle handler being called, which should process + * pending events. + */ + _handler->QueueEvent(new wxCommandEvent(wxEVT_IDLE)); + } + +private: + wxEvtHandler* _handler; +}; |
