Kaydet (Commit) 48c2815d authored tarafından Michael Meeks's avatar Michael Meeks

tdf#91727 - Unwind non-dispatch of idle handlers.

This clobbers the functionality from commit:

    06d73142

    make idle timers actually activate only when idle

Since now all rendering and re-sizing is done in idle handlers it
does effectively the opposite of what was intended. A better solution
would allow special-casing the processing of just rendering,
re-sizing and window management to spin for eg. progress bar
rendering.

Also add helpful debugging labels to the idle & timeouts.

Also cleanup the Idle vs. Scheduler handling.

Also ensure that starting an Idle triggers a mainloop wakeup.

Also add a unit test.

Change-Id: Ifb0756714378fdb790be599b93c7a3ac1f9209e6
üst ef4fd9c5
...@@ -123,7 +123,9 @@ public: ...@@ -123,7 +123,9 @@ public:
{ return (nTime <= rTime.nTime); } { return (nTime <= rTime.nTime); }
static Time GetUTCOffset(); static Time GetUTCOffset();
static sal_uInt64 GetSystemTicks(); // Elapsed time
/// Elapsed time since epoch in milliseconds
static sal_uInt64 GetSystemTicks();
void ConvertToUTC() { *this -= Time::GetUTCOffset(); } void ConvertToUTC() { *this -= Time::GetUTCOffset(); }
void ConvertToLocalTime() { *this += Time::GetUTCOffset(); } void ConvertToLocalTime() { *this += Time::GetUTCOffset(); }
......
...@@ -29,14 +29,18 @@ protected: ...@@ -29,14 +29,18 @@ protected:
Link<Idle *, void> maIdleHdl; // Callback Link Link<Idle *, void> maIdleHdl; // Callback Link
public: public:
Idle(); Idle( const sal_Char *pDebugName = NULL );
Idle( const Idle& rIdle ); Idle( const Idle& rIdle );
virtual void Start();
/// Make it possible to associate a callback with this idle handler /// Make it possible to associate a callback with this idle handler
/// of course, you can also sub-class and override 'Invoke' /// of course, you can also sub-class and override 'Invoke'
void SetIdleHdl( const Link<Idle *, void>& rLink ) { maIdleHdl = rLink; } void SetIdleHdl( const Link<Idle *, void>& rLink ) { maIdleHdl = rLink; }
const Link<Idle *, void>& GetIdleHdl() const { return maIdleHdl; } const Link<Idle *, void>& GetIdleHdl() const { return maIdleHdl; }
virtual void Invoke() SAL_OVERRIDE; virtual void Invoke() SAL_OVERRIDE;
virtual bool ReadyForSchedule( bool bTimer ) SAL_OVERRIDE;
virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) SAL_OVERRIDE;
Idle& operator=( const Idle& rIdle ); Idle& operator=( const Idle& rIdle );
}; };
......
...@@ -52,23 +52,27 @@ enum class SchedulerPriority { ...@@ -52,23 +52,27 @@ enum class SchedulerPriority {
class VCL_DLLPUBLIC Scheduler class VCL_DLLPUBLIC Scheduler
{ {
protected: protected:
ImplSchedulerData* mpSchedulerData; // Pointer to element in scheduler list ImplSchedulerData* mpSchedulerData; /// Pointer to element in scheduler list
SchedulerPriority mePriority; // Scheduler priority const sal_Char *mpDebugName; /// Useful for debugging
bool mbActive; // Currently in the scheduler SchedulerPriority mePriority; /// Scheduler priority
bool mbActive; /// Currently in the scheduler
friend struct ImplSchedulerData; friend struct ImplSchedulerData;
virtual void SetDeletionFlags(); virtual void SetDeletionFlags();
virtual bool ReadyForSchedule( bool bTimer ) { return !bTimer; } virtual bool ReadyForSchedule( bool bTimer ) = 0;
virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ); virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) = 0;
public: public:
Scheduler(); Scheduler( const sal_Char *pDebugName = NULL );
Scheduler( const Scheduler& rScheduler ); Scheduler( const Scheduler& rScheduler );
virtual ~Scheduler(); virtual ~Scheduler();
void SetPriority( SchedulerPriority ePriority ); void SetPriority( SchedulerPriority ePriority );
SchedulerPriority GetPriority() const { return mePriority; } SchedulerPriority GetPriority() const { return mePriority; }
void SetDebugName( const sal_Char *pDebugName ) { mpDebugName = pDebugName; }
const sal_Char *GetDebugName() { return mpDebugName; }
// Call handler // Call handler
virtual void Invoke() = 0; virtual void Invoke() = 0;
......
...@@ -38,7 +38,7 @@ private: ...@@ -38,7 +38,7 @@ private:
static void InitSystemTimer(); static void InitSystemTimer();
public: public:
Timer(); Timer( const sal_Char *pDebugName = NULL );
Timer( const Timer& rTimer ); Timer( const Timer& rTimer );
/// Make it possible to associate a callback with this timer handler /// Make it possible to associate a callback with this timer handler
......
...@@ -805,6 +805,7 @@ void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const ...@@ -805,6 +805,7 @@ void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const
} }
GraphicCache::GraphicCache( sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) : GraphicCache::GraphicCache( sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) :
maReleaseTimer ( "GraphicCache maReleaseTimer" ),
mnReleaseTimeoutSeconds ( 0UL ), mnReleaseTimeoutSeconds ( 0UL ),
mnMaxDisplaySize ( nDisplayCacheSize ), mnMaxDisplaySize ( nDisplayCacheSize ),
mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ), mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ),
......
...@@ -102,6 +102,7 @@ OLEObjCache::OLEObjCache() ...@@ -102,6 +102,7 @@ OLEObjCache::OLEObjCache()
pTimer->SetTimeoutHdl(aLink); pTimer->SetTimeoutHdl(aLink);
pTimer->SetTimeout(20000); pTimer->SetTimeout(20000);
pTimer->Start(); pTimer->Start();
pTimer->SetDebugName("OLEObjCache pTimer UnloadCheck");
aLink.Call(pTimer); aLink.Call(pTimer);
} }
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#include <vcl/timer.hxx> #include <vcl/timer.hxx>
#include <vcl/idle.hxx> #include <vcl/idle.hxx>
#include <vcl/svapp.hxx> #include <vcl/svapp.hxx>
#include "svdata.hxx"
#include "salinst.hxx"
// #define TEST_WATCHDOG
/// Avoid our timer tests just wedging the build if they fail. /// Avoid our timer tests just wedging the build if they fail.
class WatchDog : public osl::Thread class WatchDog : public osl::Thread
...@@ -47,6 +51,7 @@ class TimerTest : public test::BootstrapFixture ...@@ -47,6 +51,7 @@ class TimerTest : public test::BootstrapFixture
public: public:
TimerTest() : BootstrapFixture(true, false) {} TimerTest() : BootstrapFixture(true, false) {}
void testIdleMainloop();
void testIdle(); void testIdle();
#ifdef TEST_WATCHDOG #ifdef TEST_WATCHDOG
void testWatchdog(); void testWatchdog();
...@@ -58,6 +63,7 @@ public: ...@@ -58,6 +63,7 @@ public:
CPPUNIT_TEST_SUITE(TimerTest); CPPUNIT_TEST_SUITE(TimerTest);
CPPUNIT_TEST(testIdle); CPPUNIT_TEST(testIdle);
CPPUNIT_TEST(testIdleMainloop);
#ifdef TEST_WATCHDOG #ifdef TEST_WATCHDOG
CPPUNIT_TEST(testWatchdog); CPPUNIT_TEST(testWatchdog);
#endif #endif
...@@ -105,7 +111,25 @@ void TimerTest::testIdle() ...@@ -105,7 +111,25 @@ void TimerTest::testIdle()
bool bTriggered = false; bool bTriggered = false;
IdleBool aTest( bTriggered ); IdleBool aTest( bTriggered );
Scheduler::ProcessTaskScheduling(false); Scheduler::ProcessTaskScheduling(false);
CPPUNIT_ASSERT_MESSAGE("watchdog triggered", bTriggered); CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered);
}
// tdf#91727
void TimerTest::testIdleMainloop()
{
bool bTriggered = false;
IdleBool aTest( bTriggered );
while (!bTriggered)
{
ImplSVData* pSVData = ImplGetSVData();
// can't test this via Application::Yield since this
// also processes all tasks directly via the scheduler.
pSVData->maAppData.mnDispatchLevel++;
pSVData->mpDefInst->Yield( true, false );
pSVData->maAppData.mnDispatchLevel--;
}
CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
*/ */
#include <vcl/idle.hxx> #include <vcl/idle.hxx>
#include <vcl/timer.hxx>
#include "svdata.hxx"
void Idle::Invoke() void Idle::Invoke()
{ {
...@@ -31,7 +33,7 @@ Idle& Idle::operator=( const Idle& rIdle ) ...@@ -31,7 +33,7 @@ Idle& Idle::operator=( const Idle& rIdle )
return *this; return *this;
} }
Idle::Idle() : Scheduler() Idle::Idle( const sal_Char *pDebugName ) : Scheduler( pDebugName )
{ {
} }
...@@ -40,4 +42,25 @@ Idle::Idle( const Idle& rIdle ) : Scheduler(rIdle) ...@@ -40,4 +42,25 @@ Idle::Idle( const Idle& rIdle ) : Scheduler(rIdle)
maIdleHdl = rIdle.maIdleHdl; maIdleHdl = rIdle.maIdleHdl;
} }
void Idle::Start()
{
Scheduler::Start();
ImplSVData* pSVData = ImplGetSVData();
Timer::ImplStartTimer( pSVData, 0 );
}
bool Idle::ReadyForSchedule( bool bTimer )
{
// tdf#91727 - We need to re-work this to allow only UI idle handlers
// and not timeouts to be processed in some limited scenarios
(void)bTimer;
return true; // !bTimer
}
sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTime */ )
{
return 1;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -120,6 +120,7 @@ void Scheduler::ProcessTaskScheduling( bool bTimer ) ...@@ -120,6 +120,7 @@ void Scheduler::ProcessTaskScheduling( bool bTimer )
sal_uInt64 nMinPeriod = MAX_TIMER_PERIOD; sal_uInt64 nMinPeriod = MAX_TIMER_PERIOD;
pSVData->mnUpdateStack++; pSVData->mnUpdateStack++;
// tdf#91727 - NB. bTimer is ultimately not used
if ((pSchedulerData = ImplSchedulerData::GetMostImportantTask(bTimer))) if ((pSchedulerData = ImplSchedulerData::GetMostImportantTask(bTimer)))
{ {
pSchedulerData->mnUpdateTime = nTime; pSchedulerData->mnUpdateTime = nTime;
...@@ -164,18 +165,12 @@ void Scheduler::ProcessTaskScheduling( bool bTimer ) ...@@ -164,18 +165,12 @@ void Scheduler::ProcessTaskScheduling( bool bTimer )
pSVData->mnTimerPeriod = MAX_TIMER_PERIOD; pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
} }
else else
{
Timer::ImplStartTimer( pSVData, nMinPeriod ); Timer::ImplStartTimer( pSVData, nMinPeriod );
}
pSVData->mnUpdateStack--; pSVData->mnUpdateStack--;
} }
sal_uInt64 Scheduler::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime )
{
// this period is only useful for timer
// so in this implementation it' only a pass through
(void)nTime;
return nMinPeriod;
}
void Scheduler::SetPriority( SchedulerPriority ePriority ) void Scheduler::SetPriority( SchedulerPriority ePriority )
{ {
mePriority = ePriority; mePriority = ePriority;
...@@ -235,8 +230,9 @@ Scheduler& Scheduler::operator=( const Scheduler& rScheduler ) ...@@ -235,8 +230,9 @@ Scheduler& Scheduler::operator=( const Scheduler& rScheduler )
return *this; return *this;
} }
Scheduler::Scheduler(): Scheduler::Scheduler(const sal_Char *pDebugName):
mpSchedulerData(NULL), mpSchedulerData(NULL),
mpDebugName(pDebugName),
mePriority(SchedulerPriority::HIGH), mePriority(SchedulerPriority::HIGH),
mbActive(false) mbActive(false)
{ {
...@@ -244,6 +240,7 @@ Scheduler::Scheduler(): ...@@ -244,6 +240,7 @@ Scheduler::Scheduler():
Scheduler::Scheduler( const Scheduler& rScheduler ): Scheduler::Scheduler( const Scheduler& rScheduler ):
mpSchedulerData(NULL), mpSchedulerData(NULL),
mpDebugName(rScheduler.mpDebugName),
mePriority(rScheduler.mePriority), mePriority(rScheduler.mePriority),
mbActive(false) mbActive(false)
{ {
......
...@@ -98,7 +98,7 @@ void Timer::InitSystemTimer() ...@@ -98,7 +98,7 @@ void Timer::InitSystemTimer()
} }
} }
Timer::Timer() : Scheduler() Timer::Timer(const sal_Char *pDebugName) : Scheduler(pDebugName)
{ {
mnTimeout = 1; mnTimeout = 1;
mbAuto = false; mbAuto = false;
......
...@@ -1058,9 +1058,11 @@ void Window::ImplInit( vcl::Window* pParent, WinBits nStyle, SystemParentData* p ...@@ -1058,9 +1058,11 @@ void Window::ImplInit( vcl::Window* pParent, WinBits nStyle, SystemParentData* p
{ {
mpWindowImpl->mpFrameData->maPaintIdle.SetPriority( SchedulerPriority::REPAINT ); mpWindowImpl->mpFrameData->maPaintIdle.SetPriority( SchedulerPriority::REPAINT );
mpWindowImpl->mpFrameData->maPaintIdle.SetIdleHdl( LINK( this, Window, ImplHandlePaintHdl ) ); mpWindowImpl->mpFrameData->maPaintIdle.SetIdleHdl( LINK( this, Window, ImplHandlePaintHdl ) );
mpWindowImpl->mpFrameData->maPaintIdle.SetDebugName( "vcl::Window maPaintIdle" );
} }
mpWindowImpl->mpFrameData->maResizeIdle.SetPriority( SchedulerPriority::RESIZE ); mpWindowImpl->mpFrameData->maResizeIdle.SetPriority( SchedulerPriority::RESIZE );
mpWindowImpl->mpFrameData->maResizeIdle.SetIdleHdl( LINK( this, Window, ImplHandleResizeTimerHdl ) ); mpWindowImpl->mpFrameData->maResizeIdle.SetIdleHdl( LINK( this, Window, ImplHandleResizeTimerHdl ) );
mpWindowImpl->mpFrameData->maResizeIdle.SetDebugName( "vcl::Window maResizeIdle" );
mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = false; mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = false;
if ( pRealParent && IsTopWindow() ) if ( pRealParent && IsTopWindow() )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment