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 <caolan.mcnamara@collabora.com>
This commit is contained in:
committed by
Caolán McNamara
parent
2a62fe6a6b
commit
f7d0ddb247
@@ -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" };
|
||||
};
|
||||
|
||||
@@ -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(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user