summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2024-05-24 21:32:27 +0100
committerMichael Meeks <michael.meeks@collabora.com>2024-05-25 14:57:23 +0200
commitc28bcfd7a0c40e8c839a14868e211b7ff003cde5 (patch)
tree4fff4c083d9a5ecf6857d5143595dda87fe110ff /framework
parent4d2c41e8171139e210d94b0c3c2b6b3d6392665a (diff)
WakeupThread - re-factor to have a single shared wakeup thread.
The WakeupThread is an attempt to avoid needing to call gettimeofday and/or update a visual status bar very regularly, and to have a thread marking the passing of time to emit progress updates infrequently. Re-factor this to have a single time-keeping thread, so it will be easier to shutdown and re-start for LOK; and also to simplify some of the complexity lurking here. Change-Id: Ia95890e5d6041a029484aa3f7df13b59a0397086 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167949 Reviewed-by: Michael Meeks <michael.meeks@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'framework')
-rw-r--r--framework/inc/helper/statusindicatorfactory.hxx2
-rw-r--r--framework/inc/helper/wakeupthread.hxx17
-rw-r--r--framework/source/helper/statusindicatorfactory.cxx13
-rw-r--r--framework/source/helper/wakeupthread.cxx152
4 files changed, 144 insertions, 40 deletions
diff --git a/framework/inc/helper/statusindicatorfactory.hxx b/framework/inc/helper/statusindicatorfactory.hxx
index 007607e1d543..1bb07f1a0c08 100644
--- a/framework/inc/helper/statusindicatorfactory.hxx
+++ b/framework/inc/helper/statusindicatorfactory.hxx
@@ -150,7 +150,7 @@ class StatusIndicatorFactory final : public ::cppu::WeakImplHelper<
/** Notify us if a fix time is over. We use it to implement an
intelligent "Reschedule" ... */
- rtl::Reference<WakeUpThread> m_pWakeUp;
+ std::unique_ptr<WakeUpThread> m_pWakeUp;
/** Our WakeUpThread calls us in our interface method "XUpdatable::update().
There we set this member m_bAllowReschedule to sal_True. Next time if our impl_reschedule()
diff --git a/framework/inc/helper/wakeupthread.hxx b/framework/inc/helper/wakeupthread.hxx
index cdc8700a5266..b25a933dc8c8 100644
--- a/framework/inc/helper/wakeupthread.hxx
+++ b/framework/inc/helper/wakeupthread.hxx
@@ -23,9 +23,6 @@
#include <com/sun/star/uno/Reference.hxx>
#include <cppuhelper/weakref.hxx>
-#include <condition_variable>
-#include <mutex>
-#include <salhelper/thread.hxx>
namespace com::sun::star::util
{
@@ -34,19 +31,17 @@ class XUpdatable;
namespace framework
{
-class WakeUpThread final : public salhelper::Thread
+/// Provides a regular callback to @updatable roughly every 25ms while running
+class WakeUpThread final
{
- css::uno::WeakReference<css::util::XUpdatable> updatable_;
- std::condition_variable condition_;
- std::mutex mutex_;
- bool terminate_;
-
- void execute() override;
+ css::uno::Reference<css::util::XUpdatable> _updatable;
public:
WakeUpThread(css::uno::Reference<css::util::XUpdatable> const& updatable);
-
void stop();
+
+ static void joinThread();
+ static void startThread();
};
}
diff --git a/framework/source/helper/statusindicatorfactory.cxx b/framework/source/helper/statusindicatorfactory.cxx
index 9ac4022f60dd..6bf526e340b4 100644
--- a/framework/source/helper/statusindicatorfactory.cxx
+++ b/framework/source/helper/statusindicatorfactory.cxx
@@ -544,24 +544,19 @@ void StatusIndicatorFactory::impl_startWakeUpThread()
if (m_bDisableReschedule)
return;
- if (!m_pWakeUp.is())
- {
- m_pWakeUp = new WakeUpThread(this);
- m_pWakeUp->launch();
- }
+ if (!m_pWakeUp)
+ m_pWakeUp.reset(new WakeUpThread(this));
}
void StatusIndicatorFactory::impl_stopWakeUpThread()
{
- rtl::Reference<WakeUpThread> wakeUp;
+ std::unique_ptr<WakeUpThread> wakeUp;
{
std::scoped_lock g(m_mutex);
std::swap(wakeUp, m_pWakeUp);
}
- if (wakeUp.is())
- {
+ if (wakeUp)
wakeUp->stop();
- }
}
} // namespace framework
diff --git a/framework/source/helper/wakeupthread.cxx b/framework/source/helper/wakeupthread.cxx
index 40487c83b88f..63d52a82da76 100644
--- a/framework/source/helper/wakeupthread.cxx
+++ b/framework/source/helper/wakeupthread.cxx
@@ -21,40 +21,154 @@
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/util/XUpdatable.hpp>
+#include <rtl/ref.hxx>
+#include <osl/thread.hxx>
+#include <salhelper/thread.hxx>
+#include <condition_variable>
+#include <chrono>
+#include <vector>
+#include <mutex>
#include <helper/wakeupthread.hxx>
-#include <chrono>
using namespace std::chrono_literals;
-void framework::WakeUpThread::execute() {
- for (;;) {
+/// We only need one thread to wake everyone up.
+
+namespace
+{
+class SharedWakeUpThread final : public salhelper::Thread
+{
+ static std::vector<css::uno::WeakReference<css::util::XUpdatable>> updatables;
+ std::condition_variable condition;
+ bool terminate;
+
+public:
+ static rtl::Reference<SharedWakeUpThread> wakeupThread;
+
+ static std::mutex& getMutex()
+ {
+ static std::mutex mutex;
+ return mutex;
+ }
+
+ SharedWakeUpThread()
+ : Thread("WakeUpThread")
+ , terminate(false)
+ {
+ assert(!wakeupThread);
+ launch();
+ }
+
+ void execute() override
+ {
+ while (true)
{
- std::unique_lock g(mutex_);
- condition_.wait_for(g, 25ms, [this] { return terminate_; });
- if (terminate_) {
+ std::unique_lock g(getMutex());
+ condition.wait_for(g, 25ms, [this] { return terminate; });
+ if (terminate || updatables.empty())
break;
+
+ auto copyOfUpdatables = updatables;
+ g.unlock();
+
+ for (auto& it : copyOfUpdatables)
+ {
+ css::uno::Reference<css::util::XUpdatable> up(it);
+ if (up.is()) // check weak
+ up->update();
}
}
- css::uno::Reference<css::util::XUpdatable> up(updatable_);
- if (up.is()) {
- up->update();
+
+ std::unique_lock g(getMutex());
+ if (updatables.empty())
+ {
+ terminate = false;
+ wakeupThread.clear();
}
}
-}
-framework::WakeUpThread::WakeUpThread(
- css::uno::Reference<css::util::XUpdatable> const & updatable):
- Thread("WakeUpThread"), updatable_(updatable), terminate_(false)
-{}
+ static void startThread()
+ {
+ std::unique_lock g(getMutex());
+ if (!updatables.empty() && !wakeupThread)
+ wakeupThread = new SharedWakeUpThread();
+ }
-void framework::WakeUpThread::stop() {
+ void stopWithLock(std::unique_lock<std::mutex>& g)
{
- std::unique_lock g(mutex_);
- terminate_ = true;
+ terminate = true;
+ condition.notify_one();
+ g.unlock();
+
+ join();
}
- condition_.notify_one();
- join();
+
+ static void disposeThreadWithLock(std::unique_lock<std::mutex>& g)
+ {
+ if (wakeupThread)
+ {
+ auto holdRef = wakeupThread;
+ wakeupThread.clear();
+ holdRef->stopWithLock(g);
+ }
+ assert(!wakeupThread);
+ }
+
+ static void add(css::uno::WeakReference<css::util::XUpdatable> up)
+ {
+ std::unique_lock g(getMutex());
+ updatables.push_back(up);
+ if (!wakeupThread)
+ wakeupThread = new SharedWakeUpThread();
+ }
+
+ static void remove(css::uno::WeakReference<css::util::XUpdatable> up)
+ {
+ std::unique_lock g(getMutex());
+ auto it = updatables.begin();
+ bool found = false;
+ for (; it != updatables.end(); ++it)
+ {
+ css::uno::Reference<css::util::XUpdatable> itValid(*it);
+ if (!itValid || *it == up)
+ {
+ it = updatables.erase(it);
+ found = true;
+ break;
+ }
+ }
+ (void)found; assert(found);
+ if (updatables.empty())
+ disposeThreadWithLock(g);
+ }
+
+ static void joinThread()
+ {
+ std::unique_lock g(getMutex());
+ disposeThreadWithLock(g);
+ }
+};
+
+rtl::Reference<SharedWakeUpThread> SharedWakeUpThread::wakeupThread;
+std::vector<css::uno::WeakReference<css::util::XUpdatable>> SharedWakeUpThread::updatables;
}
+namespace framework
+{
+/* static */ void WakeUpThread::startThread() { SharedWakeUpThread::startThread(); }
+
+WakeUpThread::WakeUpThread(css::uno::Reference<css::util::XUpdatable> const& up)
+ : _updatable(up)
+{
+ assert(_updatable);
+ SharedWakeUpThread::add(_updatable);
+}
+
+void WakeUpThread::stop() { SharedWakeUpThread::remove(_updatable); }
+
+/* static */ void WakeUpThread::joinThread() { SharedWakeUpThread::joinThread(); }
+
+} // namespace framework
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */