summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2017-01-23 11:56:41 +0100
committerJan-Marek Glogowski <glogow@fbihome.de>2017-07-13 12:10:20 +0200
commitc0710abfebd320903a3edb23d4b1441ea351b0be (patch)
treed0a02eceed8c830cfc7a1da2bc7d14d70c8a69aa
parentdc63cc326ee5757124cef45e470d290e6e32002e (diff)
Add some Scheduler unit tests and logging
1. calling Start() for invoked tasks 2. correctly schedule by priority 3. self-stopping AutoTimer This also adds SAL_INFO output to Scheduler and Task to log the scheduling processing tasks. Change-Id: I3c8a708d1fd51c550320f8af3f9486c43c32e358
-rw-r--r--include/vcl/svapp.hxx13
-rw-r--r--vcl/inc/headless/svpinst.hxx1
-rw-r--r--vcl/inc/osx/salinst.h3
-rw-r--r--vcl/inc/salinst.hxx1
-rw-r--r--vcl/inc/saltimer.hxx12
-rw-r--r--vcl/inc/unx/gtk/gtkinst.hxx2
-rw-r--r--vcl/inc/unx/salinst.h1
-rw-r--r--vcl/inc/win/salinst.h1
-rw-r--r--vcl/osx/salinst.cxx8
-rw-r--r--vcl/osx/saltimer.cxx2
-rw-r--r--vcl/qa/cppunit/timer.cxx123
-rw-r--r--vcl/source/app/scheduler.cxx80
-rw-r--r--vcl/source/app/svapp.cxx28
-rw-r--r--vcl/unx/kde4/KDESalInstance.cxx7
-rw-r--r--vcl/unx/kde4/KDESalInstance.hxx20
-rw-r--r--vcl/win/app/salinst.cxx14
16 files changed, 265 insertions, 51 deletions
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
index 0891859c79e1..c108d4b6d992 100644
--- a/include/vcl/svapp.hxx
+++ b/include/vcl/svapp.hxx
@@ -462,18 +462,25 @@ public:
*/
static void Quit();
- /** Attempt to reschedule in processing of current event(s)
+ /** Attempt to process current pending event(s)
+
+ It doesn't sleep if no events are available for processing.
@param bAllEvents If set to true, then try to process all the
events. If set to false, then only process the current
event. Defaults to false.
+ @returns true if any event was processed.
+
@see Execute, Quit, Yield, EndYield, GetSolarMutex,
GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
*/
- static void Reschedule( bool bAllEvents = false );
+ static bool Reschedule( bool bAllEvents = false );
+
+ /** Process the next event.
- /** Allow processing of the next event.
+ It sleeps if no event is available for processing and just returns
+ if an event was processed.
@see Execute, Quit, Reschedule, EndYield, GetSolarMutex,
GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx
index 731642f5762c..4a82c413372a 100644
--- a/vcl/inc/headless/svpinst.hxx
+++ b/vcl/inc/headless/svpinst.hxx
@@ -157,6 +157,7 @@ public:
// and timer
virtual SalYieldResult DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
virtual bool AnyInput( VclInputFlags nType ) override;
+ virtual bool IsMainThread() const override { return true; }
// may return NULL to disable session management
virtual SalSession* CreateSalSession() override;
diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h
index 6570ab32a7e2..b92a2aa35665 100644
--- a/vcl/inc/osx/salinst.h
+++ b/vcl/inc/osx/salinst.h
@@ -142,7 +142,8 @@ public:
void PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData );
void delayedSettingsChanged( bool bInvalidate );
- bool isNSAppThread() const;
+ // Is this the NSAppThread?
+ virtual bool IsMainThread() const override;
void startedPrintJob() { mnActivePrintJobs++; }
void endedPrintJob() { mnActivePrintJobs--; }
diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx
index ca8017d94513..0e2703af8999 100644
--- a/vcl/inc/salinst.hxx
+++ b/vcl/inc/salinst.hxx
@@ -127,6 +127,7 @@ public:
virtual void AcquireYieldMutex( sal_uLong nCount ) = 0;
// return true, if yield mutex is owned by this thread, else false
virtual bool CheckYieldMutex() = 0;
+ virtual bool IsMainThread() const = 0;
/**
* Wait for the next event (if bWait) and dispatch it,
diff --git a/vcl/inc/saltimer.hxx b/vcl/inc/saltimer.hxx
index 234a18228af2..fcf450d28a7b 100644
--- a/vcl/inc/saltimer.hxx
+++ b/vcl/inc/saltimer.hxx
@@ -21,10 +21,9 @@
#define INCLUDED_VCL_INC_SALTIMER_HXX
#include <sal/config.h>
-
#include <vcl/dllapi.h>
-
#include <salwtype.hxx>
+#include <iostream>
/*
* note: there will be only a single instance of SalTimer
@@ -72,6 +71,15 @@ struct ImplSchedulerData
const char *GetDebugName() const;
};
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const ImplSchedulerData& data )
+{
+ stream << " i: " << data.mbInScheduler
+ << " d: " << data.mbDelete;
+ return stream;
+}
+
#endif // INCLUDED_VCL_INC_SALTIMER_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
index 250fd9b1ca1b..983fbf287deb 100644
--- a/vcl/inc/unx/gtk/gtkinst.hxx
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
@@ -210,6 +210,8 @@ public:
virtual SalYieldResult DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
virtual bool AnyInput( VclInputFlags nType ) override;
+ // impossible to handle correctly, as "main thread" depends on the dispatch mutex
+ virtual bool IsMainThread() const override { return false; }
virtual GenPspGraphics *CreatePrintGraphics() override;
diff --git a/vcl/inc/unx/salinst.h b/vcl/inc/unx/salinst.h
index f3ca193df205..1f9c43bf2232 100644
--- a/vcl/inc/unx/salinst.h
+++ b/vcl/inc/unx/salinst.h
@@ -76,6 +76,7 @@ public:
virtual SalYieldResult DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
virtual bool AnyInput( VclInputFlags nType ) override;
+ virtual bool IsMainThread() const override { return true; }
virtual OUString GetConnectionIdentifier() override;
void SetLib( SalXLib *pXLib ) { mpXLib = pXLib; }
diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h
index 25b4afb17aa0..022f67e0557a 100644
--- a/vcl/inc/win/salinst.h
+++ b/vcl/inc/win/salinst.h
@@ -62,6 +62,7 @@ public:
virtual sal_uIntPtr ReleaseYieldMutex() override;
virtual void AcquireYieldMutex( sal_uIntPtr nCount ) override;
virtual bool CheckYieldMutex() override;
+ virtual bool IsMainThread() const override;
virtual SalYieldResult DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) override;
virtual bool AnyInput( VclInputFlags nType ) override;
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index 0a1dd479af0d..c73f94685f07 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -445,7 +445,7 @@ bool AquaSalInstance::CheckYieldMutex()
return bRet;
}
-bool AquaSalInstance::isNSAppThread() const
+bool AquaSalInstance::IsMainThread() const
{
return osl::Thread::getCurrentIdentifier() == maMainThread;
}
@@ -607,7 +607,7 @@ SalYieldResult AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents
// handle cocoa event queue
// cocoa events may be only handled in the thread the NSApp was created
bool bHadEvent = false;
- if( isNSAppThread() && mnActivePrintJobs == 0 )
+ if( IsMainThread() && mnActivePrintJobs == 0 )
{
// we need to be woken up by a cocoa-event
// if a user event should be posted by the event handling below
@@ -742,7 +742,7 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType )
}
}
- if (![NSThread isMainThread])
+ if (!IsMainThread())
return false;
unsigned/*NSUInteger*/ nEventMask = 0;
@@ -1019,7 +1019,7 @@ OUString AquaSalInstance::getOSVersion()
YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
{
SalData* pSalData = GetSalData();
- if( ! pSalData->mpFirstInstance->isNSAppThread() )
+ if( ! pSalData->mpFirstInstance->IsMainThread() )
{
SalData::ensureThreadAutoreleasePool();
mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex();
diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx
index b28a6598cec6..9b2c1df83c83 100644
--- a/vcl/osx/saltimer.cxx
+++ b/vcl/osx/saltimer.cxx
@@ -33,7 +33,7 @@ bool AquaSalTimer::bDispatchTimer = false;
void ImplSalStartTimer( sal_uLong nMS )
{
SalData* pSalData = GetSalData();
- if( pSalData->mpFirstInstance->isNSAppThread() )
+ if( !pSalData->mpFirstInstance->IsMainThread() )
{
AquaSalTimer::bDispatchTimer = true;
NSTimeInterval aTI = double(nMS)/1000.0;
diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx
index 47439ad19e8b..83b0a7cc01e5 100644
--- a/vcl/qa/cppunit/timer.cxx
+++ b/vcl/qa/cppunit/timer.cxx
@@ -64,9 +64,12 @@ public:
void testAutoTimer();
void testMultiAutoTimers();
#endif
- void testRecursiveTimer();
+ void testAutoTimerStop();
+ void testNestedTimer();
void testSlowTimerCallback();
void testTriggerIdleFromIdle();
+ void testInvokedReStart();
+ void testPriority();
CPPUNIT_TEST_SUITE(TimerTest);
CPPUNIT_TEST(testIdle);
@@ -79,9 +82,12 @@ public:
CPPUNIT_TEST(testAutoTimer);
CPPUNIT_TEST(testMultiAutoTimers);
#endif
- CPPUNIT_TEST(testRecursiveTimer);
+ CPPUNIT_TEST(testAutoTimerStop);
+ CPPUNIT_TEST(testNestedTimer);
CPPUNIT_TEST(testSlowTimerCallback);
CPPUNIT_TEST(testTriggerIdleFromIdle);
+ CPPUNIT_TEST(testInvokedReStart);
+ CPPUNIT_TEST(testPriority);
CPPUNIT_TEST_SUITE_END();
};
@@ -100,7 +106,7 @@ class IdleBool : public Idle
bool &mrBool;
public:
explicit IdleBool( bool &rBool ) :
- Idle(), mrBool( rBool )
+ Idle( "IdleBool" ), mrBool( rBool )
{
SetPriority( TaskPriority::LOWEST );
Start();
@@ -117,7 +123,7 @@ void TimerTest::testIdle()
{
bool bTriggered = false;
IdleBool aTest( bTriggered );
- Scheduler::ProcessTaskScheduling( true );
+ while ( Application::Reschedule() );
CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered);
}
@@ -148,7 +154,7 @@ class TimerBool : public Timer
bool &mrBool;
public:
TimerBool( sal_uLong nMS, bool &rBool ) :
- Timer(), mrBool( rBool )
+ Timer( "TimerBool" ), mrBool( rBool )
{
SetTimeout( nMS );
Start();
@@ -180,17 +186,26 @@ void TimerTest::testDurations()
class AutoTimerCount : public AutoTimer
{
sal_Int32 &mrCount;
+ const sal_Int32 mnMaxCount;
+
public:
- AutoTimerCount( sal_uLong nMS, sal_Int32 &rCount ) :
- AutoTimer(), mrCount( rCount )
+ AutoTimerCount( sal_uLong nMS, sal_Int32 &rCount,
+ const sal_Int32 nMaxCount = -1 )
+ : AutoTimer( "AutoTimerCount" )
+ , mrCount( rCount )
+ , mnMaxCount( nMaxCount )
{
SetTimeout( nMS );
Start();
mrCount = 0;
}
+
virtual void Invoke() override
{
- mrCount++;
+ ++mrCount;
+ CPPUNIT_ASSERT( mnMaxCount < 0 || mrCount <= mnMaxCount );
+ if ( mrCount == mnMaxCount )
+ Stop();
}
};
@@ -296,11 +311,22 @@ void TimerTest::testMultiAutoTimers()
}
#endif // TEST_TIMERPRECISION
+void TimerTest::testAutoTimerStop()
+{
+ sal_Int32 nTimerCount = 0;
+ const sal_Int32 nMaxCount = 5;
+ AutoTimerCount aAutoTimer( 0, nTimerCount, nMaxCount );
+ while ( nMaxCount != nTimerCount )
+ Application::Yield();
+ CPPUNIT_ASSERT( !aAutoTimer.IsActive() );
+ CPPUNIT_ASSERT( !Application::Reschedule() );
+}
+
class YieldTimer : public Timer
{
public:
- explicit YieldTimer( sal_uLong nMS ) : Timer()
+ explicit YieldTimer( sal_uLong nMS ) : Timer( "YieldTimer" )
{
SetTimeout( nMS );
Start();
@@ -312,7 +338,7 @@ public:
}
};
-void TimerTest::testRecursiveTimer()
+void TimerTest::testNestedTimer()
{
sal_Int32 nCount = 0;
YieldTimer aCount(5);
@@ -328,7 +354,7 @@ class SlowCallbackTimer : public Timer
bool &mbSlow;
public:
SlowCallbackTimer( sal_uLong nMS, bool &bBeenSlow ) :
- Timer(), mbSlow( bBeenSlow )
+ Timer( "SlowCallbackTimer" ), mbSlow( bBeenSlow )
{
SetTimeout( nMS );
Start();
@@ -362,7 +388,7 @@ class TriggerIdleFromIdle : public Idle
TriggerIdleFromIdle* mpOther;
public:
explicit TriggerIdleFromIdle( bool* pTriggered, TriggerIdleFromIdle* pOther ) :
- Idle(), mpTriggered(pTriggered), mpOther(pOther)
+ Idle( "TriggerIdleFromIdle" ), mpTriggered(pTriggered), mpOther(pOther)
{
}
virtual void Invoke() override
@@ -388,6 +414,79 @@ void TimerTest::testTriggerIdleFromIdle()
CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered2);
}
+
+class IdleInvokedReStart : public Idle
+{
+ sal_Int32 &mrCount;
+public:
+ IdleInvokedReStart( sal_Int32 &rCount )
+ : Idle( "IdleInvokedReStart" ), mrCount( rCount )
+ {
+ Start();
+ }
+ virtual void Invoke() override
+ {
+ mrCount++;
+ if ( mrCount < 2 )
+ Start();
+ }
+};
+
+void TimerTest::testInvokedReStart()
+{
+ sal_Int32 nCount = 0;
+ IdleInvokedReStart aIdle( nCount );
+ while ( Application::Reschedule() );
+ CPPUNIT_ASSERT_EQUAL( nCount, sal_Int32(2) );
+}
+
+
+class IdleSerializer : public Idle
+{
+ sal_uInt32 mnPosition;
+ sal_uInt32 &mrProcesed;
+public:
+ IdleSerializer( const sal_Char *pDebugName,
+ sal_uInt32 nPosition, sal_uInt32 &rProcesed )
+ : Idle( pDebugName )
+ , mnPosition( nPosition )
+ , mrProcesed( rProcesed )
+ {
+ Start();
+ }
+ virtual void Invoke() override
+ {
+ ++mrProcesed;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Ignored prio", mnPosition, mrProcesed );
+ }
+};
+
+void TimerTest::testPriority()
+{
+ // scope, so tasks are deleted
+ {
+ // Start: 1st Idle low, 2nd high
+ sal_uInt32 nProcessed = 0;
+ IdleSerializer aLowPrioIdle( "IdleSerializer LowPrio", 2, nProcessed );
+ aLowPrioIdle.SetPriority( TaskPriority::LOWEST );
+ IdleSerializer aHighPrioIdle( "IdleSerializer HighPrio", 1, nProcessed );
+ aHighPrioIdle.SetPriority( TaskPriority::HIGHEST );
+ while ( Application::Reschedule() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed );
+ }
+
+ {
+ // Start: 1st Idle high, 2nd low
+ sal_uInt32 nProcessed = 0;
+ IdleSerializer aHighPrioIdle( "IdleSerializer HighPrio", 1, nProcessed );
+ aHighPrioIdle.SetPriority( TaskPriority::HIGHEST );
+ IdleSerializer aLowPrioIdle( "IdleSerializer LowPrio", 2, nProcessed );
+ aLowPrioIdle.SetPriority( TaskPriority::LOWEST );
+ while ( Application::Reschedule() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed );
+ }
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index 1c52ad170d28..2b372a6616e0 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -19,13 +19,58 @@
#include <svdata.hxx>
#include <tools/time.hxx>
-#include <vcl/scheduler.hxx>
+#include <vcl/idle.hxx>
#include <saltimer.hxx>
#include <salinst.hxx>
#include <comphelper/profilezone.hxx>
namespace {
const sal_uInt64 MaximumTimeoutMs = 1000 * 60; // 1 minute
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Task& task )
+{
+ stream << "a: " << task.IsActive() << " p: " << (int) task.GetPriority();
+ const sal_Char *name = task.GetDebugName();
+ if( nullptr == name )
+ return stream << " (nullptr)";
+ else
+ return stream << " " << name;
+}
+
+/**
+ * clang won't compile this in the Timer.hxx header, even with a class Idle
+ * forward definition, due to the incomplete Idle type in the template.
+ * Currently the code is just used in the Scheduler, so we keep it local.
+ *
+ * @see http://clang.llvm.org/compatibility.html#undep_incomplete
+ */
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Timer& timer )
+{
+ bool bIsIdle = (dynamic_cast<const Idle*>( &timer ) != nullptr);
+ stream << (bIsIdle ? "Idle " : "Timer")
+ << " a: " << timer.IsActive() << " p: " << (int) timer.GetPriority();
+ const sal_Char *name = timer.GetDebugName();
+ if ( nullptr == name )
+ stream << " (nullptr)";
+ else
+ stream << " " << name;
+ if ( !bIsIdle )
+ stream << " " << timer.GetTimeout() << "ms";
+ stream << " (" << &timer << ")";
+ return stream;
+}
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Idle& idle )
+{
+ return stream << static_cast<const Timer*>( &idle );
+}
+
}
void ImplSchedulerData::Invoke()
@@ -140,6 +185,7 @@ bool Scheduler::ProcessTaskScheduling( bool bIdle )
!pSchedulerData->mpTask->ReadyForSchedule( bIdle, nTime ) ||
!pSchedulerData->mpTask->IsActive())
continue;
+
if (!pMostUrgent)
pMostUrgent = pSchedulerData;
else
@@ -156,7 +202,8 @@ bool Scheduler::ProcessTaskScheduling( bool bIdle )
{
::comphelper::ProfileZone aZone( pMostUrgent->GetDebugName() );
- SAL_INFO("vcl.schedule", "Invoke task " << pMostUrgent->GetDebugName());
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pMostUrgent << " invoke " << *pMostUrgent->mpTask );
pMostUrgent->mnUpdateTime = nTime;
pMostUrgent->Invoke();
@@ -192,6 +239,18 @@ sal_uInt64 Scheduler::CalculateMinimumTimeout( bool &bHasActiveIdles )
pSchedulerData = pSVData->mpFirstSchedulerData;
while ( pSchedulerData )
{
+ const Timer *timer = dynamic_cast<Timer*>( pSchedulerData->mpTask );
+ if ( timer )
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pSchedulerData << " " << *pSchedulerData << " " << *timer );
+ else if ( pSchedulerData->mpTask )
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pSchedulerData << " " << *pSchedulerData
+ << " " << *pSchedulerData->mpTask );
+ else
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" );
+
ImplSchedulerData *pNext = pSchedulerData->mpNext;
// Should Task be released from scheduling?
@@ -216,10 +275,6 @@ sal_uInt64 Scheduler::CalculateMinimumTimeout( bool &bHasActiveIdles )
sal_uInt64 nOldMinPeriod = nMinPeriod;
nMinPeriod = pSchedulerData->mpTask->UpdateMinPeriod(
nOldMinPeriod, nTime );
- SAL_INFO("vcl.schedule", "Have active timer '" <<
- pSchedulerData->GetDebugName() <<
- "' update min period from " << nOldMinPeriod <<
- " to " << nMinPeriod);
assert( nMinPeriod <= nOldMinPeriod );
if ( nMinPeriod > nOldMinPeriod )
{
@@ -229,11 +284,7 @@ sal_uInt64 Scheduler::CalculateMinimumTimeout( bool &bHasActiveIdles )
}
}
else
- {
- SAL_INFO("vcl.schedule", "Have active idle '" <<
- pSchedulerData->GetDebugName() << "'");
bHasActiveIdles = true;
- }
}
pPrevSchedulerData = pSchedulerData;
}
@@ -309,15 +360,22 @@ void Task::Start()
pPrev->mpNext = mpSchedulerData;
else
pSVData->mpFirstSchedulerData = mpSchedulerData;
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
+ << " " << mpSchedulerData << " added " << *this );
}
+ else
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
+ << " " << mpSchedulerData << " restarted " << *this );
+
mpSchedulerData->mbDelete = false;
mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks();
}
void Task::Stop()
{
+ SAL_INFO_IF( mbActive, "vcl.schedule", tools::Time::GetSystemTicks()
+ << " " << mpSchedulerData << " stopped " << *this );
mbActive = false;
-
if ( mpSchedulerData )
mpSchedulerData->mbDelete = true;
}
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index c4d22d397013..fff8619d51fc 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -516,9 +516,9 @@ inline bool ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased
return bHasActiveIdles || eResult == SalYieldResult::EVENT;
}
-void Application::Reschedule( bool i_bAllEvents )
+bool Application::Reschedule( bool i_bAllEvents )
{
- ImplYield(false, i_bAllEvents, 0);
+ return ImplYield(false, i_bAllEvents, 0);
}
void Scheduler::ProcessEventsToSignal(bool& bSignal)
@@ -541,6 +541,30 @@ void Scheduler::ProcessEventsToIdle()
break;
}
}
+#if OSL_DEBUG_LEVEL > 0
+ // If we yield from a non-main thread we just can guarantee that all idle
+ // events were processed at some point, but our check can't prevent further
+ // processing in the main thread, which may add new events, so skip it.
+ const ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mpDefInst->IsMainThread() )
+ return;
+ const ImplSchedulerData* pSchedulerData = ImplGetSVData()->mpFirstSchedulerData;
+ bool bAnyIdle = false;
+ while ( pSchedulerData )
+ {
+ if ( pSchedulerData->mpTask && !pSchedulerData->mbInScheduler )
+ {
+ Idle *pIdle = dynamic_cast<Idle*>( pSchedulerData->mpTask );
+ if ( pIdle && pIdle->IsActive() )
+ {
+ bAnyIdle = true;
+ SAL_WARN( "vcl.schedule", "Unprocessed Idle: " << pIdle->GetDebugName() );
+ }
+ }
+ pSchedulerData = pSchedulerData->mpNext;
+ }
+ assert( !bAnyIdle );
+#endif
}
extern "C" {
diff --git a/vcl/unx/kde4/KDESalInstance.cxx b/vcl/unx/kde4/KDESalInstance.cxx
index dfe02cd36e2e..56f3df9465cb 100644
--- a/vcl/unx/kde4/KDESalInstance.cxx
+++ b/vcl/unx/kde4/KDESalInstance.cxx
@@ -25,6 +25,8 @@
#include "KDEXLib.hxx"
#include "KDESalDisplay.hxx"
+#include <QtGui/QApplication>
+#include <QtCore/QThread>
#include <QX11Info>
using namespace com::sun::star;
@@ -58,4 +60,9 @@ SalX11Display* KDESalInstance::CreateDisplay() const
return new SalKDEDisplay( QX11Info::display() );
}
+bool KDESalInstance::IsMainThread() const
+{
+ return qApp->thread() == QThread::currentThread();
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde4/KDESalInstance.hxx b/vcl/unx/kde4/KDESalInstance.hxx
index 54a0b405d96f..7b7417caaaf1 100644
--- a/vcl/unx/kde4/KDESalInstance.hxx
+++ b/vcl/unx/kde4/KDESalInstance.hxx
@@ -26,18 +26,20 @@ class SalFrame;
class KDESalInstance : public X11SalInstance
{
- protected:
- virtual SalX11Display* CreateDisplay() const override;
+protected:
+ virtual SalX11Display* CreateDisplay() const override;
- public:
- explicit KDESalInstance(SalYieldMutex* pMutex);
- virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override;
+public:
+ explicit KDESalInstance(SalYieldMutex* pMutex);
+ virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override;
- virtual bool hasNativeFileSelection() const override { return true; }
+ virtual bool hasNativeFileSelection() const override { return true; }
- virtual css::uno::Reference< css::ui::dialogs::XFilePicker2 >
- createFilePicker( const css::uno::Reference<
- css::uno::XComponentContext >& ) override;
+ virtual css::uno::Reference< css::ui::dialogs::XFilePicker2 >
+ createFilePicker( const css::uno::Reference<
+ css::uno::XComponentContext >& ) override;
+
+ virtual bool IsMainThread() const override;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index 78147ae67608..1fbdda70b261 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -188,10 +188,7 @@ void ImplSalYieldMutexAcquireWithWait()
if ( !pInst )
return;
- DWORD nThreadId = GetCurrentThreadId();
- SalData* pSalData = GetSalData();
-
- if ( pSalData->mnAppThreadId == nThreadId )
+ if ( pInst->IsMainThread() )
{
// tdf#96887 If this is the main thread, then we must wait for two things:
// - the mpSalYieldMutex being freed
@@ -594,13 +591,18 @@ ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
SalYieldResult::TIMEOUT;
}
+bool WinSalInstance::IsMainThread() const
+{
+ const SalData* pSalData = GetSalData();
+ return pSalData->mnAppThreadId == GetCurrentThreadId();
+}
+
SalYieldResult WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
{
SalYieldResult eDidWork = SalYieldResult::TIMEOUT;
// NOTE: if nReleased != 0 this will be called without SolarMutex
// so don't do anything dangerous before releasing it here
SalYieldMutex* pYieldMutex = mpSalYieldMutex;
- SalData* pSalData = GetSalData();
DWORD nCurThreadId = GetCurrentThreadId();
sal_uLong const nCount = (nReleased != 0)
? nReleased
@@ -611,7 +613,7 @@ SalYieldResult WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents,
pYieldMutex->release();
n--;
}
- if ( pSalData->mnAppThreadId != nCurThreadId )
+ if ( !IsMainThread() )
{
// #97739# A SendMessage call blocks until the called thread (here: the main thread)
// returns. During a yield however, messages are processed in the main thread that might