diff options
-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 ); } |