Kaydet (Commit) b22526b8 authored tarafından Jan-Marek Glogowski's avatar Jan-Marek Glogowski

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
üst d93acb77
......@@ -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:
......
......@@ -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):
......
......@@ -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
......
......@@ -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 );
}
......
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