summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2017-01-25 15:49:44 +0100
committerJan-Marek Glogowski <glogow@fbihome.de>2017-07-13 12:10:22 +0200
commitb22526b8ad88f5061b1901914e280ba9c8db1fe7 (patch)
treed91c6d8845e2e37f5c822037cd66edfc441413ab
parentd93acb77667ecdb78b53a1be626ca2e000813828 (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.hxx4
-rw-r--r--solenv/gdb/libreoffice/vcl.py5
-rw-r--r--vcl/inc/svdata.hxx1
-rw-r--r--vcl/source/app/scheduler.cxx108
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 );
}