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: ...@@ -46,6 +46,22 @@ public:
virtual void Start() override; 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 #endif // INCLUDED_VCL_IDLE_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -70,6 +70,7 @@ public: ...@@ -70,6 +70,7 @@ public:
void testTriggerIdleFromIdle(); void testTriggerIdleFromIdle();
void testInvokedReStart(); void testInvokedReStart();
void testPriority(); void testPriority();
void testRoundRobin();
CPPUNIT_TEST_SUITE(TimerTest); CPPUNIT_TEST_SUITE(TimerTest);
CPPUNIT_TEST(testIdle); CPPUNIT_TEST(testIdle);
...@@ -88,6 +89,7 @@ public: ...@@ -88,6 +89,7 @@ public:
CPPUNIT_TEST(testTriggerIdleFromIdle); CPPUNIT_TEST(testTriggerIdleFromIdle);
CPPUNIT_TEST(testInvokedReStart); CPPUNIT_TEST(testInvokedReStart);
CPPUNIT_TEST(testPriority); CPPUNIT_TEST(testPriority);
CPPUNIT_TEST(testRoundRobin);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
}; };
...@@ -487,6 +489,46 @@ void TimerTest::testPriority() ...@@ -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_TEST_SUITE_REGISTRATION(TimerTest);
CPPUNIT_PLUGIN_IMPLEMENT(); CPPUNIT_PLUGIN_IMPLEMENT();
......
...@@ -67,4 +67,9 @@ sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTi ...@@ -67,4 +67,9 @@ sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nMinPeriod */, sal_uInt64 /* nTi
return Scheduler::ImmediateTimeoutMs; return Scheduler::ImmediateTimeoutMs;
} }
AutoIdle::AutoIdle( const sal_Char *pDebugName )
: Idle( true, pDebugName )
{
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -234,6 +234,22 @@ static inline void AppendSchedulerData( ImplSchedulerContext &rSchedCtx, ...@@ -234,6 +234,22 @@ static inline void AppendSchedulerData( ImplSchedulerContext &rSchedCtx,
pSchedulerData->mpNext = nullptr; 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() bool Scheduler::ProcessTaskScheduling()
{ {
ImplSVData *pSVData = ImplGetSVData(); ImplSVData *pSVData = ImplGetSVData();
...@@ -246,6 +262,7 @@ bool Scheduler::ProcessTaskScheduling() ...@@ -246,6 +262,7 @@ bool Scheduler::ProcessTaskScheduling()
ImplSchedulerData* pSchedulerData = nullptr; ImplSchedulerData* pSchedulerData = nullptr;
ImplSchedulerData* pPrevSchedulerData = nullptr; ImplSchedulerData* pPrevSchedulerData = nullptr;
ImplSchedulerData *pMostUrgent = nullptr; ImplSchedulerData *pMostUrgent = nullptr;
ImplSchedulerData *pPrevMostUrgent = nullptr;
sal_uInt64 nMinPeriod = InfiniteTimeoutMs; sal_uInt64 nMinPeriod = InfiniteTimeoutMs;
DBG_TESTSOLARMUTEX(); DBG_TESTSOLARMUTEX();
...@@ -268,13 +285,8 @@ bool Scheduler::ProcessTaskScheduling() ...@@ -268,13 +285,8 @@ bool Scheduler::ProcessTaskScheduling()
// Should the Task be released from scheduling or stacked? // Should the Task be released from scheduling or stacked?
if ( pSchedulerData->mbDelete || !pSchedulerData->mpTask || pSchedulerData->mbInScheduler ) if ( pSchedulerData->mbDelete || !pSchedulerData->mpTask || pSchedulerData->mbInScheduler )
{ {
ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext; ImplSchedulerData * const pSchedulerDataNext =
if ( pPrevSchedulerData ) DropSchedulerData( rSchedCtx, pPrevSchedulerData, pSchedulerData );
pPrevSchedulerData->mpNext = pSchedulerDataNext;
else
rSchedCtx.mpFirstSchedulerData = pSchedulerDataNext;
if ( !pSchedulerDataNext )
rSchedCtx.mpLastSchedulerData = pPrevSchedulerData;
if ( pSchedulerData->mbInScheduler ) if ( pSchedulerData->mbInScheduler )
{ {
pSchedulerData->mpNext = rSchedCtx.mpSchedulerStack; pSchedulerData->mpNext = rSchedCtx.mpSchedulerStack;
...@@ -300,6 +312,7 @@ bool Scheduler::ProcessTaskScheduling() ...@@ -300,6 +312,7 @@ bool Scheduler::ProcessTaskScheduling()
{ {
if ( pMostUrgent ) if ( pMostUrgent )
UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod ); UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod );
pPrevMostUrgent = pPrevSchedulerData;
pMostUrgent = pSchedulerData; pMostUrgent = pSchedulerData;
} }
else else
...@@ -344,11 +357,21 @@ next_entry: ...@@ -344,11 +357,21 @@ next_entry:
UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true, UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
tools::Time::GetSystemTicks() ); tools::Time::GetSystemTicks() );
} }
else if ( pMostUrgent->mpTask && !pMostUrgent->mbDelete ) else
{ {
pMostUrgent->mnUpdateTime = tools::Time::GetSystemTicks(); // Since we can restart tasks, round-robin all non-last tasks
UpdateMinPeriod( pMostUrgent, nTime, nMinPeriod ); if ( pMostUrgent->mpNext )
UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime ); {
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