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

Round-robin invoked tasks

Add some round-robin to the task processing, so equal priority
(auto) tasks won't always be scheduled, if there are multiple
tasks with the same priority.

Change-Id: Ice111aa5f85e9181b3ee9799ca4df0d58f210fe9
üst 23beae53
......@@ -46,6 +46,22 @@ public:
virtual void Start() override;
};
/**
* An auto-idle is long running task processing small chunks of data, which
* is re-scheduled multiple times.
*
* Remember to stop the Idle when finished, as it would otherwise busy loop the CPU!
*
* It probably makes sense to re-implement ReadyForSchedule and UpdateMinPeriod,
* in case there is a quick check and it can otherwise sleep.
*/
class VCL_DLLPUBLIC AutoIdle : public Idle
{
public:
AutoIdle( const sal_Char *pDebugName = nullptr );
};
#endif // INCLUDED_VCL_IDLE_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -70,6 +70,7 @@ public:
void testTriggerIdleFromIdle();
void testInvokedReStart();
void testPriority();
void testRoundRobin();
CPPUNIT_TEST_SUITE(TimerTest);
CPPUNIT_TEST(testIdle);
......@@ -88,6 +89,7 @@ public:
CPPUNIT_TEST(testTriggerIdleFromIdle);
CPPUNIT_TEST(testInvokedReStart);
CPPUNIT_TEST(testPriority);
CPPUNIT_TEST(testRoundRobin);
CPPUNIT_TEST_SUITE_END();
};
......@@ -487,6 +489,46 @@ void TimerTest::testPriority()
}
}
class TestAutoIdleRR : public AutoIdle
{
sal_uInt32 &mrCount;
DECL_LINK( IdleRRHdl, Timer *, void );
public:
TestAutoIdleRR( sal_uInt32 &rCount,
const sal_Char *pDebugName )
: AutoIdle( pDebugName )
, mrCount( rCount )
{
CPPUNIT_ASSERT_EQUAL( mrCount, sal_uInt32(0) );
SetInvokeHandler( LINK( this, TestAutoIdleRR, IdleRRHdl ) );
Start();
}
};
IMPL_LINK_NOARG(TestAutoIdleRR, IdleRRHdl, Timer *, void)
{
++mrCount;
if ( mrCount == 3 )
Stop();
}
void TimerTest::testRoundRobin()
{
sal_uInt32 nCount1 = 0, nCount2 = 0;
TestAutoIdleRR aIdle1( nCount1, "TestAutoIdleRR aIdle1" ),
aIdle2( nCount2, "TestAutoIdleRR aIdle2" );
while ( Application::Reschedule() )
{
CPPUNIT_ASSERT( nCount1 == nCount2 || nCount1 - 1 == nCount2 );
CPPUNIT_ASSERT( nCount1 <= 3 );
CPPUNIT_ASSERT( nCount2 <= 3 );
}
CPPUNIT_ASSERT( 3 == nCount1 && 3 == nCount2 );
}
CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest);
CPPUNIT_PLUGIN_IMPLEMENT();
......
......@@ -67,4 +67,9 @@ sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTi
return Scheduler::ImmediateTimeoutMs;
}
AutoIdle::AutoIdle( const sal_Char *pDebugName )
: Idle( true, pDebugName )
{
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -234,6 +234,22 @@ static inline void AppendSchedulerData( ImplSchedulerContext &rSchedCtx,
pSchedulerData->mpNext = nullptr;
}
static inline ImplSchedulerData* DropSchedulerData(
ImplSchedulerContext &rSchedCtx, ImplSchedulerData * const pPrevSchedulerData,
ImplSchedulerData * const pSchedulerData )
{
assert( !pPrevSchedulerData || (pPrevSchedulerData->mpNext == pSchedulerData) );
ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext;
if ( pPrevSchedulerData )
pPrevSchedulerData->mpNext = pSchedulerDataNext;
else
rSchedCtx.mpFirstSchedulerData = pSchedulerDataNext;
if ( !pSchedulerDataNext )
rSchedCtx.mpLastSchedulerData = pPrevSchedulerData;
return pSchedulerDataNext;
}
bool Scheduler::ProcessTaskScheduling()
{
ImplSVData *pSVData = ImplGetSVData();
......@@ -246,6 +262,7 @@ bool Scheduler::ProcessTaskScheduling()
ImplSchedulerData* pSchedulerData = nullptr;
ImplSchedulerData* pPrevSchedulerData = nullptr;
ImplSchedulerData *pMostUrgent = nullptr;
ImplSchedulerData *pPrevMostUrgent = nullptr;
sal_uInt64 nMinPeriod = InfiniteTimeoutMs;
DBG_TESTSOLARMUTEX();
......@@ -268,13 +285,8 @@ bool Scheduler::ProcessTaskScheduling()
// 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 = pSchedulerDataNext;
else
rSchedCtx.mpFirstSchedulerData = pSchedulerDataNext;
if ( !pSchedulerDataNext )
rSchedCtx.mpLastSchedulerData = pPrevSchedulerData;
ImplSchedulerData * const pSchedulerDataNext =
DropSchedulerData( rSchedCtx, pPrevSchedulerData, pSchedulerData );
if ( pSchedulerData->mbInScheduler )
{
pSchedulerData->mpNext = rSchedCtx.mpSchedulerStack;
......@@ -300,6 +312,7 @@ bool Scheduler::ProcessTaskScheduling()
{
if ( pMostUrgent )
UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod );
pPrevMostUrgent = pPrevSchedulerData;
pMostUrgent = pSchedulerData;
}
else
......@@ -344,11 +357,21 @@ next_entry:
UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
tools::Time::GetSystemTicks() );
}
else if ( pMostUrgent->mpTask && !pMostUrgent->mbDelete )
else
{
pMostUrgent->mnUpdateTime = tools::Time::GetSystemTicks();
UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod );
UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
// Since we can restart tasks, round-robin all non-last tasks
if ( pMostUrgent->mpNext )
{
DropSchedulerData( rSchedCtx, pPrevMostUrgent, pMostUrgent );
AppendSchedulerData( rSchedCtx, pMostUrgent );
}
if ( pMostUrgent->mpTask && !pMostUrgent->mbDelete )
{
pMostUrgent->mnUpdateTime = nTime;
UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod );
UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
}
}
}
......
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