desktop/source/lib/init.cxx |   53 ++++++++++++++++++++++++-------
 include/salhelper/timer.hxx |    8 ++++
 salhelper/source/gcc3.map   |    5 ++
 salhelper/source/timer.cxx  |   75 ++++++++++++++++++++++++++++++++++++--------
 4 files changed, 116 insertions(+), 25 deletions(-)

New commits:
commit 645746365891acf277534c62f2a3fc0c8ccd7f89
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Wed May 21 17:53:20 2025 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Thu May 22 11:57:18 2025 +0200

    join restartable threads on large trimMemory effort
    
    Change-Id: Ibbb1471fb1436e7894cdc6946410a88e52dd50c9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185627
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    (cherry picked from commit b5f44b5f68dcb814771a6eec29ed92fdb56d93d2)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185642
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 7e312ad1a3ab..40e522c635fe 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -3336,6 +3336,18 @@ static char* 
lo_extractDocumentStructureRequest(LibreOfficeKit* /*pThis*/, const
     return strdup("{ }");
 }
 
+namespace {
+
+enum class JoinThreads
+{
+    ALL,
+    RESTARTS_ON_DEMAND
+};
+
+}
+
+static int joinThreads(JoinThreads eCategory);
+
 static void lo_trimMemory(LibreOfficeKit* /* pThis */, int nTarget)
 {
     vcl::lok::trimMemory(nTarget);
@@ -3368,6 +3380,10 @@ static void lo_trimMemory(LibreOfficeKit* /* pThis */, 
int nTarget)
                 }
             }
         }
+
+        // When more agressively reclaiming memory then shutdown threads which
+        // will restart on demand.
+        joinThreads(JoinThreads::RESTARTS_ON_DEMAND);
     }
 
     if (nTarget > 1000)
@@ -3545,8 +3561,7 @@ static void lo_stopURP(LibreOfficeKit* /* pThis */,
     
static_cast<FunctionBasedURPConnection*>(pFunctionBasedURPConnection)->close();
 }
 
-
-static int lo_joinThreads(LibreOfficeKit* /* pThis */)
+static int joinThreads(JoinThreads eCategory)
 {
     comphelper::ThreadPool &pool = 
comphelper::ThreadPool::getSharedOptimalPool();
     if (!pool.joinThreadsIfIdle())
@@ -3560,17 +3575,20 @@ static int lo_joinThreads(LibreOfficeKit* /* pThis */)
     if (joinable && !joinable->joinThreads())
         return 0;
 
-    auto ucpWebdav = xContext->getServiceManager()->createInstanceWithContext(
-        "com.sun.star.ucb.WebDAVManager", xContext);
-    joinable = dynamic_cast<comphelper::LibreOfficeKit::ThreadJoinable 
*>(ucpWebdav.get());
-    if (joinable && !joinable->joinThreads())
-        return 0;
+    if (eCategory == JoinThreads::ALL)
+    {
+        auto ucpWebdav = 
xContext->getServiceManager()->createInstanceWithContext(
+            "com.sun.star.ucb.WebDAVManager", xContext);
+        joinable = dynamic_cast<comphelper::LibreOfficeKit::ThreadJoinable 
*>(ucpWebdav.get());
+        if (joinable && !joinable->joinThreads())
+            return 0;
 
-    auto progressThread = 
xContext->getServiceManager()->createInstanceWithContext(
-        "com.sun.star.task.StatusIndicatorFactory", xContext);
-    joinable = dynamic_cast<comphelper::LibreOfficeKit::ThreadJoinable 
*>(progressThread.get());
-    if (joinable && !joinable->joinThreads())
-        return 0;
+        auto progressThread = 
xContext->getServiceManager()->createInstanceWithContext(
+            "com.sun.star.task.StatusIndicatorFactory", xContext);
+        joinable = dynamic_cast<comphelper::LibreOfficeKit::ThreadJoinable 
*>(progressThread.get());
+        if (joinable && !joinable->joinThreads())
+            return 0;
+    }
 
     // Ensure configmgr's write thread is down
     css::uno::Reference< css::util::XFlushable >(
@@ -3578,11 +3596,17 @@ static int lo_joinThreads(LibreOfficeKit* /* pThis */)
             comphelper::getProcessComponentContext()),
         css::uno::UNO_QUERY_THROW)->flush();
 
-    salhelper::Timer::joinThread();
+    if (eCategory == JoinThreads::ALL)
+        salhelper::Timer::joinThread();
 
     return 1;
 }
 
+static int lo_joinThreads(LibreOfficeKit* /* pThis */)
+{
+    return joinThreads(JoinThreads::ALL);
+}
+
 static void lo_startThreads(LibreOfficeKit* /* pThis */)
 {
     salhelper::Timer::startThread();
commit 011760896551817d4fe8018214eff6d011bb385a
Author:     Michael Meeks <michael.me...@collabora.com>
AuthorDate: Fri Mar 14 19:29:11 2025 +0000
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Thu May 22 11:57:11 2025 +0200

    Timer - shutdown and re-start salhelper::Timer thread.
    
    Necessary for lok background save.
    
    Change-Id: Ib78f67f124dcd5b2a8b50c65ea58a9e1eb894ade
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182931
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    (cherry picked from commit 79197949d757c40f750406f59e85d6efe02bf584)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185641

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 268ea05974e3..7e312ad1a3ab 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -77,6 +77,7 @@
 #include <rtl/uri.hxx>
 #include <svl/cryptosign.hxx>
 #include <linguistic/misc.hxx>
+#include <salhelper/timer.hxx>
 #include <cppuhelper/bootstrap.hxx>
 #include <comphelper/random.hxx>
 #include <comphelper/base64.hxx>
@@ -3577,11 +3578,15 @@ static int lo_joinThreads(LibreOfficeKit* /* pThis */)
             comphelper::getProcessComponentContext()),
         css::uno::UNO_QUERY_THROW)->flush();
 
+    salhelper::Timer::joinThread();
+
     return 1;
 }
 
 static void lo_startThreads(LibreOfficeKit* /* pThis */)
 {
+    salhelper::Timer::startThread();
+
     auto ucpWebdav = xContext->getServiceManager()->createInstanceWithContext(
         "com.sun.star.ucb.WebDAVManager", xContext);
     auto joinable = dynamic_cast<comphelper::LibreOfficeKit::ThreadJoinable 
*>(ucpWebdav.get());
diff --git a/include/salhelper/timer.hxx b/include/salhelper/timer.hxx
index 8c0ce5d3a2bc..3fa81785aefe 100644
--- a/include/salhelper/timer.hxx
+++ b/include/salhelper/timer.hxx
@@ -177,6 +177,14 @@ public:
      */
     TTimeValue  SAL_CALL getRemainingTime() const;
 
+    /** Internal method to shutdown the timer thread
+     */
+    static void SAL_CALL joinThread();
+
+    /** Internal method to re-start the timer thread if necessary
+     */
+    static void SAL_CALL startThread();
+
 protected:
 
     /** Destructor.
diff --git a/salhelper/source/gcc3.map b/salhelper/source/gcc3.map
index 3d0d90d4aae0..b1bbad779b31 100644
--- a/salhelper/source/gcc3.map
+++ b/salhelper/source/gcc3.map
@@ -131,6 +131,11 @@ LIBO_UDK_3.6 { # symbols available in >= LibO 3.6
             # non-virtual thunk to salhelper::Thread::run()
 } UDK_3.1;
 
+PRIVATE_1.0 {
+        _ZN9salhelper5Timer10joinThreadEv;
+        _ZN9salhelper5Timer11startThreadEv;
+};
+
 # Unique libstdc++ symbols:
 GLIBCXX_3.4 {
     global:
diff --git a/salhelper/source/timer.cxx b/salhelper/source/timer.cxx
index 07510f228cde..7a83149c867c 100644
--- a/salhelper/source/timer.cxx
+++ b/salhelper/source/timer.cxx
@@ -20,16 +20,15 @@
 
 #include <osl/thread.hxx>
 
-#include <condition_variable>
 #include <mutex>
+#include <condition_variable>
 
 using namespace salhelper;
 
 class salhelper::TimerManager final : public osl::Thread
 {
 public:
-    TimerManager();
-
+    TimerManager(salhelper::Timer* &pHead, std::mutex &Lock);
     ~TimerManager();
 
     /// register timer
@@ -48,24 +47,65 @@ protected:
     /// Checking and triggering of a timer event
     void checkForTimeout();
 
-    /// sorted-queue data
-    salhelper::Timer*       m_pHead;
+    salhelper::Timer*           &m_pHead;
     bool m_terminate;
     /// List Protection
-    std::mutex                  m_Lock;
+    std::mutex                  &m_Lock;
     /// Signal the insertion of a timer
     std::condition_variable     m_notEmpty;
 
     /// "Singleton Pattern"
     //static salhelper::TimerManager* m_pManager;
-
 };
 
-namespace
+namespace {
+class TimerManagerImpl final
 {
-    salhelper::TimerManager& getTimerManager()
+    std::mutex m_Lock; // shared lock with each impl. thread
+    salhelper::Timer* m_pHead; // the underlying shared queue
+    std::shared_ptr<TimerManager> m_pImpl;
+
+public:
+    TimerManagerImpl() : m_pHead(nullptr) { }
+
+    void joinThread()
+    {
+        m_pImpl.reset();
+    }
+
+    void startThread()
+    {
+        std::lock_guard Guard(m_Lock);
+        if (m_pHead)
+            ensureThread();
+    }
+
+    std::shared_ptr<TimerManager> ensureThread()
+    {
+        if (!m_pImpl)
+            m_pImpl.reset(new TimerManager(m_pHead, m_Lock));
+        return m_pImpl;
+    }
+
+    void registerTimer(salhelper::Timer* pTimer)
     {
-        static salhelper::TimerManager aManager;
+        ensureThread()->registerTimer(pTimer);
+    }
+
+    void unregisterTimer(salhelper::Timer * pTimer)
+    {
+        ensureThread()->unregisterTimer(pTimer);
+    }
+
+    bool lookupTimer(const salhelper::Timer* pTimer)
+    {
+        return ensureThread()->lookupTimer(pTimer);
+    }
+};
+
+    TimerManagerImpl& getTimerManager()
+    {
+        static TimerManagerImpl aManager;
         return aManager;
     }
 }
@@ -195,6 +235,16 @@ TTimeValue Timer::getRemainingTime() const
     return TTimeValue(secs, nsecs);
 }
 
+void Timer::joinThread()
+{
+    getTimerManager().joinThread();
+}
+
+void Timer::startThread()
+{
+    getTimerManager().startThread();
+}
+
 /** The timer manager cleanup has been removed (no thread is killed anymore),
     so the thread leaks.
 
@@ -205,8 +255,8 @@ TTimeValue Timer::getRemainingTime() const
             when there are no timers anymore !
 **/
 
-TimerManager::TimerManager() :
-    m_pHead(nullptr), m_terminate(false)
+TimerManager::TimerManager(salhelper::Timer* &pHead, std::mutex &Lock) :
+    m_pHead(pHead), m_terminate(false), m_Lock(Lock)
 {
     // start thread
     create();
@@ -387,7 +437,6 @@ void TimerManager::run()
 
         checkForTimeout();
     }
-
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to