summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 );
}