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(); }); } }
