Increase the life-cycle of threads in thread-pool...

to ScDocument lifetime if possible. This helps to avoid lots
of thread setup-cost while doing recalcs especially if there are
many formula-groups in the document and most of them are fairly
light-weight.

Change-Id: Idd57e1ebd0d4e492f99e31237d4a55ec9c95a121
Reviewed-on: https://gerrit.libreoffice.org/69473
Tested-by: Jenkins
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
diff --git a/comphelper/source/misc/threadpool.cxx b/comphelper/source/misc/threadpool.cxx
index d0178e9..89d8029 100644
--- a/comphelper/source/misc/threadpool.cxx
+++ b/comphelper/source/misc/threadpool.cxx
@@ -213,7 +213,7 @@ std::unique_ptr<ThreadTask> ThreadPool::popWorkLocked( std::unique_lock< std::mu
    return nullptr;
}

void ThreadPool::waitUntilDone(const std::shared_ptr<ThreadTaskTag>& rTag)
void ThreadPool::waitUntilDone(const std::shared_ptr<ThreadTaskTag>& rTag, bool bJoinAll)
{
#if defined DBG_UTIL && (defined LINUX || defined _WIN32)
    assert(!gbIsWorkerThread && "cannot wait for tasks from inside a task");
@@ -232,12 +232,16 @@ void ThreadPool::waitUntilDone(const std::shared_ptr<ThreadTaskTag>& rTag)

    rTag->waitUntilDone();

    if (bJoinAll)
        joinAll();
}

void ThreadPool::joinAll()
{
    std::unique_lock< std::mutex > aGuard( maMutex );
    if (maTasks.empty()) // check if there are still tasks from another tag
    {
        std::unique_lock< std::mutex > aGuard( maMutex );
        if (maTasks.empty()) // check if there are still tasks from another tag
        {
            shutdownLocked(aGuard);
        }
        shutdownLocked(aGuard);
    }
}

diff --git a/include/comphelper/threadpool.hxx b/include/comphelper/threadpool.hxx
index 0920781..1cb9441 100644
--- a/include/comphelper/threadpool.hxx
+++ b/include/comphelper/threadpool.hxx
@@ -63,8 +63,13 @@ public:
    /// push a new task onto the work queue
    void        pushTask( std::unique_ptr<ThreadTask> pTask);

    /// wait until all queued tasks associated with the tag are completed
    void        waitUntilDone(const std::shared_ptr<ThreadTaskTag>&);
    /** Wait until all queued tasks associated with the tag are completed
        @param  bJoinAll - if set it joins all threads at the end if no other tasks from other tags.
    */
    void        waitUntilDone(const std::shared_ptr<ThreadTaskTag>&, bool bJoinAll = true);

    /// join all threads if there are no tasks presently.
    void        joinAll();

    /// return the number of live worker threads
    sal_Int32   getWorkerCount() const { return mnWorkers; }
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 321c453..0892025b 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -32,6 +32,7 @@
#include <tools/urlobj.hxx>
#include <rtl/crc.h>
#include <basic/basmgr.hxx>
#include <comphelper/threadpool.hxx>
#include <sal/log.hxx>

#include <document.hxx>
@@ -307,6 +308,9 @@ ScDocument::~ScDocument()
{
    OSL_PRECOND( !bInLinkUpdate, "bInLinkUpdate in dtor" );

    // Join any pending(recalc) threads in global threadpool
    comphelper::ThreadPool::getSharedOptimalPool().joinAll();

    bInDtorClear = true;

    // first of all disable all refresh timers by deleting the control
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 17dc298..9edddf0 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -4758,8 +4758,10 @@ bool ScFormulaCell::InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
                                                                nStartOffset, nEndOffset));
            }

            SAL_INFO("sc.threaded", "Joining threads");
            rThreadPool.waitUntilDone(aTag);
            SAL_INFO("sc.threaded", "Waiting for threads to finish work");
            // Do not join the threads here. They will get joined in ScDocument destructor
            // if they don't get joined from elsewhere before (via ThreadPool::waitUntilDone).
            rThreadPool.waitUntilDone(aTag, false);

            pDocument->SetThreadedGroupCalcInProgress(false);