diff options
author | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-01-25 15:49:44 +0100 |
---|---|---|
committer | Jan-Marek Glogowski <glogow@fbihome.de> | 2017-07-13 12:10:22 +0200 |
commit | b22526b8ad88f5061b1901914e280ba9c8db1fe7 (patch) | |
tree | d91c6d8845e2e37f5c822037cd66edfc441413ab | |
parent | d93acb77667ecdb78b53a1be626ca2e000813828 (diff) |
Introduce a scheduler stack
While the stack removes all invoked tasks from the queue, which
actively removes it from scheduling, it also helps to faster handle
nested calls, as we don't have to look for the previous position
to move the task to the end of the queue for the round robin.
Change-Id: I358cf2492e9630f67685a2b780509edb56691830
-rw-r--r-- | include/vcl/scheduler.hxx | 4 | ||||
-rw-r--r-- | solenv/gdb/libreoffice/vcl.py | 5 | ||||
-rw-r--r-- | vcl/inc/svdata.hxx | 1 | ||||
-rw-r--r-- | vcl/source/app/scheduler.cxx | 108 |
4 files changed, 78 insertions, 40 deletions
diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx index f5edb214349a..b1c59dc0a6f5 100644 --- a/include/vcl/scheduler.hxx +++ b/include/vcl/scheduler.hxx @@ -38,6 +38,10 @@ class VCL_DLLPUBLIC Scheduler final static inline void UpdateMinPeriod( ImplSchedulerData *pSchedulerData, sal_uInt64 nTime, sal_uInt64 &nMinPeriod ); + static inline void UpdateSystemTimer( ImplSchedulerContext &rSchedCtx, + sal_uInt64 nMinPeriod, + bool bForce, sal_uInt64 nTime ); + static void ImplStartTimer ( sal_uInt64 nMS, bool bForce, sal_uInt64 nTime ); public: diff --git a/solenv/gdb/libreoffice/vcl.py b/solenv/gdb/libreoffice/vcl.py index 62dc3a06f09b..bcd10ae157e6 100644 --- a/solenv/gdb/libreoffice/vcl.py +++ b/solenv/gdb/libreoffice/vcl.py @@ -16,6 +16,11 @@ class ImplSchedulerDataPrinter(object): This can be used to dump the current state of the scheduler via: p *ImplGetSVData()->mpFirstSchedulerData + + This doesn't include currently invoked tasks AKA the stack. + + To dump the scheduler stack of invoked tasks use: + p *ImplGetSVData()->mpSchedulerStack ''' def __init__(self, typename, value): diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index dcbbc00ea9bc..844f564c425f 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -323,6 +323,7 @@ struct ImplSchedulerContext { ImplSchedulerData* mpFirstSchedulerData = nullptr; ///< list of all active tasks ImplSchedulerData* mpLastSchedulerData = nullptr; ///< last item of the mpFirstSchedulerData list + ImplSchedulerData* mpSchedulerStack = nullptr; ///< stack of invoked tasks SalTimer* mpSalTimer = nullptr; ///< interface to sal event loop / system timer sal_uInt64 mnTimerStart = 0; ///< start time of the timer sal_uInt64 mnTimerPeriod = SAL_MAX_UINT64; ///< current timer period diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 8e166a974ac2..8a332b8bb538 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -190,7 +190,7 @@ bool Scheduler::HasPendingTasks() tools::Time::GetSystemTicks() ); } -inline void Scheduler::UpdateMinPeriod( ImplSchedulerData *pSchedulerData, +inline void Scheduler::UpdateMinPeriod( ImplSchedulerData * const pSchedulerData, const sal_uInt64 nTime, sal_uInt64 &nMinPeriod ) { if ( nMinPeriod > ImmediateTimeoutMs ) @@ -203,6 +203,37 @@ inline void Scheduler::UpdateMinPeriod( ImplSchedulerData *pSchedulerData, } } +inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx, + const sal_uInt64 nMinPeriod, + const bool bForce, const sal_uInt64 nTime ) +{ + if ( InfiniteTimeoutMs == nMinPeriod ) + { + if ( rSchedCtx.mpSalTimer ) + rSchedCtx.mpSalTimer->Stop(); + SAL_INFO("vcl.schedule", " Stopping system timer"); + rSchedCtx.mnTimerPeriod = nMinPeriod; + } + else + Scheduler::ImplStartTimer( nMinPeriod, bForce, nTime ); +} + +static inline void AppendSchedulerData( ImplSchedulerContext &rSchedCtx, + ImplSchedulerData * const pSchedulerData ) +{ + if ( !rSchedCtx.mpLastSchedulerData ) + { + rSchedCtx.mpFirstSchedulerData = pSchedulerData; + rSchedCtx.mpLastSchedulerData = pSchedulerData; + } + else + { + rSchedCtx.mpLastSchedulerData->mpNext = pSchedulerData; + rSchedCtx.mpLastSchedulerData = pSchedulerData; + } + pSchedulerData->mpNext = nullptr; +} + bool Scheduler::ProcessTaskScheduling() { ImplSVData *pSVData = ImplGetSVData(); @@ -234,23 +265,28 @@ bool Scheduler::ProcessTaskScheduling() SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" ); - if ( pSchedulerData->mbInScheduler ) - goto next_entry; - - // Should Task be released from scheduling? - if ( pSchedulerData->mbDelete || !pSchedulerData->mpTask ) + // Should the Task be released from scheduling or stacked? + if ( pSchedulerData->mbDelete || !pSchedulerData->mpTask || pSchedulerData->mbInScheduler ) { + ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext; if ( pPrevSchedulerData ) - pPrevSchedulerData->mpNext = pSchedulerData->mpNext; + pPrevSchedulerData->mpNext = pSchedulerDataNext; else - rSchedCtx.mpFirstSchedulerData = pSchedulerData->mpNext; - if ( !pSchedulerData->mpNext ) + rSchedCtx.mpFirstSchedulerData = pSchedulerDataNext; + if ( !pSchedulerDataNext ) rSchedCtx.mpLastSchedulerData = pPrevSchedulerData; - if ( pSchedulerData->mpTask ) - pSchedulerData->mpTask->mpSchedulerData = nullptr; - ImplSchedulerData *pDeleteItem = pSchedulerData; - pSchedulerData = pSchedulerData->mpNext; - delete pDeleteItem; + if ( pSchedulerData->mbInScheduler ) + { + pSchedulerData->mpNext = rSchedCtx.mpSchedulerStack; + rSchedCtx.mpSchedulerStack = pSchedulerData; + } + else + { + if ( pSchedulerData->mpTask ) + pSchedulerData->mpTask->mpSchedulerData = nullptr; + delete pSchedulerData; + } + pSchedulerData = pSchedulerDataNext; continue; } @@ -272,19 +308,9 @@ next_entry: pSchedulerData = pSchedulerData->mpNext; } - // delete clock if no more timers available, - if ( InfiniteTimeoutMs == nMinPeriod ) - { - if ( pSVData->maSchedCtx.mpSalTimer ) - pSVData->maSchedCtx.mpSalTimer->Stop(); - SAL_INFO("vcl.schedule", " Stopping system timer"); - pSVData->maSchedCtx.mnTimerPeriod = nMinPeriod; - } - else - { - Scheduler::ImplStartTimer( nMinPeriod, true, nTime ); + if ( InfiniteTimeoutMs != nMinPeriod ) SAL_INFO("vcl.schedule", "Calculated minimum timeout as " << nMinPeriod ); - } + UpdateSystemTimer( rSchedCtx, nMinPeriod, true, nTime ); if ( pMostUrgent ) { @@ -298,12 +324,25 @@ next_entry: // prepare Scheduler object for deletion after handling pTask->SetDeletionFlags(); - // invoke it + // invoke the task + // defer pushing the scheduler stack to next run, as most tasks will + // not run a nested Scheduler loop and don't need a stack push! pMostUrgent->mbInScheduler = true; pTask->Invoke(); pMostUrgent->mbInScheduler = false; - if ( pMostUrgent->mpTask && !pMostUrgent->mbDelete ) + // eventually pop the scheduler stack + // this just happens for nested calls, which renders all accounting + // invalid, so we just enforce a rescheduling! + if ( pMostUrgent == pSVData->maSchedCtx.mpSchedulerStack ) + { + pSchedulerData = pSVData->maSchedCtx.mpSchedulerStack; + pSVData->maSchedCtx.mpSchedulerStack = pSchedulerData->mpNext; + AppendSchedulerData( rSchedCtx, pSchedulerData ); + UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true, + tools::Time::GetSystemTicks() ); + } + else if ( pMostUrgent->mpTask && !pMostUrgent->mbDelete ) pMostUrgent->mnUpdateTime = tools::Time::GetSystemTicks(); } @@ -341,20 +380,9 @@ void Task::Start() ImplSchedulerData* pSchedulerData = new ImplSchedulerData; pSchedulerData->mpTask = this; pSchedulerData->mbInScheduler = false; - pSchedulerData->mpNext = nullptr; mpSchedulerData = pSchedulerData; - // insert last due to SFX! - if ( !rSchedCtx.mpLastSchedulerData ) - { - rSchedCtx.mpFirstSchedulerData = pSchedulerData; - rSchedCtx.mpLastSchedulerData = pSchedulerData; - } - else - { - rSchedCtx.mpLastSchedulerData->mpNext = pSchedulerData; - rSchedCtx.mpLastSchedulerData = pSchedulerData; - } + AppendSchedulerData( rSchedCtx, pSchedulerData ); SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " << mpSchedulerData << " added " << *this ); } |