include/vcl/idletask.hxx       |    7 +++++++
 vcl/source/helper/idletask.cxx |   18 +++++++++++++++---
 2 files changed, 22 insertions(+), 3 deletions(-)

New commits:
commit f7d0ddb247e17c7fa36928621a63765104d3cefe
Author:     Neil Roberts <[email protected]>
AuthorDate: Tue Nov 18 17:05:14 2025 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Wed Nov 19 20:18:33 2025 +0100

    idletask: Wait with a condition_variable when not on the main thread
    
    Judging by the comment that was in waitUntilIdleDispatched, I think the
    intention of this helper class is to wait until the main loop is idle
    and that any event processing has actually completed. However, if this
    is called outside of the main thread then that doesn’t work if the event
    processing temporarily releases the solar mutex. In that case, the
    thread that is waiting for the IdleTask flag would wake up and set the
    flag itself even though the main thread hasn’t actually finished
    executing its event handling code yet.
    
    To fix that this patch makes it instead wait with a
    std::condition_variable instead of Yield when not running on the main
    thread so that we can be sure that the main thread will invoke the idle
    task instead of the waiting thread.
    
    Change-Id: Ib5c6efe31dfb5e1a5039b43702e23bf0104cd403
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194180
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/include/vcl/idletask.hxx b/include/vcl/idletask.hxx
index 1b8e33b7b181..3c038626e496 100644
--- a/include/vcl/idletask.hxx
+++ b/include/vcl/idletask.hxx
@@ -12,6 +12,8 @@
 #include <sal/config.h>
 #include <vcl/dllapi.h>
 #include <vcl/idle.hxx>
+#include <condition_variable>
+#include <mutex>
 
 //IdleTask class to add a low priority Idle task
 class VCL_DLLPUBLIC IdleTask
@@ -27,6 +29,11 @@ public:
 
 private:
     DECL_LINK(FlipFlag, Timer*, void);
+
+    // Mutex and condition variable used to signal flag
+    std::mutex mFlagMutex;
+    std::condition_variable mFlagCv;
+
     bool flag;
     Idle maIdle{ "testtool IdleTask" };
 };
diff --git a/vcl/source/helper/idletask.cxx b/vcl/source/helper/idletask.cxx
index 2865d8d0367a..9c4c10df205f 100644
--- a/vcl/source/helper/idletask.cxx
+++ b/vcl/source/helper/idletask.cxx
@@ -32,19 +32,31 @@ bool IdleTask::GetFlag() const
 //Callback function of IdleTask Class
 IMPL_LINK(IdleTask, FlipFlag, Timer*, , void)
 {
+    std::lock_guard aGuard(mFlagMutex);
     //setting the flag to make sure that low priority idle task has been 
dispatched
     flag = true;
+    mFlagCv.notify_all();
 }
 
 void IdleTask::waitUntilIdleDispatched()
 {
     //creating instance of IdleTask Class
     IdleTask idleTask;
-    while (!idleTask.GetFlag())
+
+    if (Application::IsMainThread())
     {
-        //dispatching all the events via VCL main-loop
         SolarMutexGuard aGuard;
-        Application::Yield();
+        while (!idleTask.GetFlag())
+            Application::Yield();
+    }
+    else
+    {
+        // We don’t want to wait with Yield because that can cause this thread 
to execute the idle
+        // task. If the main thread is processing an event and temporarily 
releases the solar mutex
+        // then that would cause this function to finish before the event 
processing in the main
+        // thread actually finishes.
+        std::unique_lock aLock(idleTask.mFlagMutex);
+        idleTask.mFlagCv.wait(aLock, [&idleTask] { return idleTask.GetFlag(); 
});
     }
 }
 

Reply via email to