framework/inc/helper/statusindicatorfactory.hxx    |    2 
 framework/inc/helper/wakeupthread.hxx              |   17 --
 framework/source/helper/statusindicatorfactory.cxx |   13 -
 framework/source/helper/wakeupthread.cxx           |  152 ++++++++++++++++++---
 4 files changed, 144 insertions(+), 40 deletions(-)

New commits:
commit c28bcfd7a0c40e8c839a14868e211b7ff003cde5
Author:     Michael Meeks <michael.me...@collabora.com>
AuthorDate: Fri May 24 21:32:27 2024 +0100
Commit:     Michael Meeks <michael.me...@collabora.com>
CommitDate: Sat May 25 14:57:23 2024 +0200

    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.me...@collabora.com>
    Tested-by: Jenkins

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: */

Reply via email to