diff options
author | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-01-23 11:56:41 +0100 |
---|---|---|
committer | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-07-13 12:10:20 +0200 |
commit | c0710abfebd320903a3edb23d4b1441ea351b0be (patch) | |
tree | d0a02eceed8c830cfc7a1da2bc7d14d70c8a69aa | |
parent | dc63cc326ee5757124cef45e470d290e6e32002e (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.hxx | 13 | ||||
-rw-r--r-- | vcl/inc/headless/svpinst.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/osx/salinst.h | 3 | ||||
-rw-r--r-- | vcl/inc/salinst.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/saltimer.hxx | 12 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkinst.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/salinst.h | 1 | ||||
-rw-r--r-- | vcl/inc/win/salinst.h | 1 | ||||
-rw-r--r-- | vcl/osx/salinst.cxx | 8 | ||||
-rw-r--r-- | vcl/osx/saltimer.cxx | 2 | ||||
-rw-r--r-- | vcl/qa/cppunit/timer.cxx | 123 | ||||
-rw-r--r-- | vcl/source/app/scheduler.cxx | 80 | ||||
-rw-r--r-- | vcl/source/app/svapp.cxx | 28 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalInstance.cxx | 7 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalInstance.hxx | 20 | ||||
-rw-r--r-- | vcl/win/app/salinst.cxx | 14 |
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 |