From aea4a919933d721931f65d81391bf2b13b0f79aa Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 8 Aug 2013 11:49:15 +0200 Subject: smp: Optimize Simple SMP scheduler Add Thread_Control::is_in_the_air field if configured for SMP. This helps to simplify the extract operation and avoids superfluous inter-processor interrupts. Move the processor allocation step into the enqueue operation. Add and use _Scheduler_simple_smp_Get_highest_ready(). Add and use _Scheduler_SMP_Get_lowest_scheduled(). --- cpukit/score/src/schedulersimplesmp.c | 137 ++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 33 deletions(-) (limited to 'cpukit/score/src/schedulersimplesmp.c') diff --git a/cpukit/score/src/schedulersimplesmp.c b/cpukit/score/src/schedulersimplesmp.c index fa128f8ab1..a46f58e673 100644 --- a/cpukit/score/src/schedulersimplesmp.c +++ b/cpukit/score/src/schedulersimplesmp.c @@ -34,22 +34,42 @@ void _Scheduler_simple_smp_Initialize( void ) _Scheduler.information = self; } +static Thread_Control *_Scheduler_simple_smp_Get_highest_ready( + Scheduler_SMP_Control *self +) +{ + Thread_Control *highest_ready = NULL; + Chain_Control *ready = &self->ready[ 0 ]; + + if ( !_Chain_Is_empty( ready ) ) { + highest_ready = (Thread_Control *) _Chain_First( ready ); + } + + return highest_ready; +} + static void _Scheduler_simple_smp_Move_from_scheduled_to_ready( - Chain_Control *ready_chain, + Scheduler_SMP_Control *self, Thread_Control *scheduled_to_ready ) { _Chain_Extract_unprotected( &scheduled_to_ready->Object.Node ); - _Scheduler_simple_Insert_priority_lifo( ready_chain, scheduled_to_ready ); + _Scheduler_simple_Insert_priority_lifo( + &self->ready[ 0 ], + scheduled_to_ready + ); } static void _Scheduler_simple_smp_Move_from_ready_to_scheduled( - Chain_Control *scheduled_chain, + Scheduler_SMP_Control *self, Thread_Control *ready_to_scheduled ) { _Chain_Extract_unprotected( &ready_to_scheduled->Object.Node ); - _Scheduler_simple_Insert_priority_fifo( scheduled_chain, ready_to_scheduled ); + _Scheduler_simple_Insert_priority_fifo( + &self->scheduled, + ready_to_scheduled + ); } static void _Scheduler_simple_smp_Insert( @@ -61,6 +81,19 @@ static void _Scheduler_simple_smp_Insert( _Chain_Insert_ordered_unprotected( chain, &thread->Object.Node, order ); } +static void _Scheduler_simple_smp_Schedule_highest_ready( + Scheduler_SMP_Control *self, + Thread_Control *victim +) +{ + Thread_Control *highest_ready = + (Thread_Control *) _Chain_First( &self->ready[ 0 ] ); + + _Scheduler_SMP_Allocate_processor( highest_ready, victim ); + + _Scheduler_simple_smp_Move_from_ready_to_scheduled( self, highest_ready ); +} + static void _Scheduler_simple_smp_Enqueue_ordered( Thread_Control *thread, Chain_Node_order order @@ -68,24 +101,68 @@ static void _Scheduler_simple_smp_Enqueue_ordered( { Scheduler_SMP_Control *self = _Scheduler_SMP_Instance(); - /* - * The scheduled chain has exactly processor count nodes after - * initialization, thus the lowest priority scheduled thread exists. - */ - Thread_Control *lowest_scheduled = - (Thread_Control *) _Chain_Last( &self->scheduled ); + if ( thread->is_in_the_air ) { + Thread_Control *highest_ready = + _Scheduler_simple_smp_Get_highest_ready( self ); + + thread->is_in_the_air = false; + + /* + * The thread has been extracted from the scheduled chain. We have to + * place it now on the scheduled or ready chain. + * + * NOTE: Do not exchange parameters to do the negation of the order check. + */ + if ( + highest_ready != NULL + && !( *order )( &thread->Object.Node, &highest_ready->Object.Node ) + ) { + _Scheduler_SMP_Allocate_processor( highest_ready, thread ); + + _Scheduler_simple_smp_Insert( &self->ready[ 0 ], thread, order ); + + _Scheduler_simple_smp_Move_from_ready_to_scheduled( + self, + highest_ready + ); + } else { + thread->is_scheduled = true; + + _Scheduler_simple_smp_Insert( &self->scheduled, thread, order ); + } + } else { + Thread_Control *lowest_scheduled = _Scheduler_SMP_Get_lowest_scheduled( self ); + + /* + * The scheduled chain is empty if nested interrupts change the priority of + * all scheduled threads. These threads are in the air. + */ + if ( + lowest_scheduled != NULL + && ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node ) + ) { + _Scheduler_SMP_Allocate_processor( thread, lowest_scheduled ); + + _Scheduler_simple_smp_Insert( &self->scheduled, thread, order ); + + _Scheduler_simple_smp_Move_from_scheduled_to_ready( + self, + lowest_scheduled + ); + } else { + _Scheduler_simple_smp_Insert( &self->ready[ 0 ], thread, order ); + } + } +} - if ( ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node ) ) { - _Scheduler_SMP_Allocate_processor( thread, lowest_scheduled ); +void _Scheduler_simple_smp_Block( Thread_Control *thread ) +{ + _Chain_Extract_unprotected( &thread->Object.Node ); - _Scheduler_simple_smp_Insert( &self->scheduled, thread, order ); + if ( thread->is_scheduled ) { + Scheduler_SMP_Control *self = _Scheduler_SMP_Instance(); - _Scheduler_simple_smp_Move_from_scheduled_to_ready( - &self->ready[ 0 ], - lowest_scheduled - ); - } else { - _Scheduler_simple_smp_Insert( &self->ready[ 0 ], thread, order ); + _Scheduler_simple_smp_Schedule_highest_ready( self, thread ); } } @@ -107,21 +184,9 @@ void _Scheduler_simple_smp_Enqueue_priority_fifo( Thread_Control *thread ) void _Scheduler_simple_smp_Extract( Thread_Control *thread ) { - Scheduler_SMP_Control *self = _Scheduler_SMP_Instance(); + thread->is_in_the_air = true; _Chain_Extract_unprotected( &thread->Object.Node ); - - if ( thread->is_scheduled ) { - Thread_Control *highest_ready = - (Thread_Control *) _Chain_First( &self->ready[ 0 ] ); - - _Scheduler_SMP_Allocate_processor( highest_ready, thread ); - - _Scheduler_simple_smp_Move_from_ready_to_scheduled( - &self->scheduled, - highest_ready - ); - } } void _Scheduler_simple_smp_Yield( Thread_Control *thread ) @@ -138,5 +203,11 @@ void _Scheduler_simple_smp_Yield( Thread_Control *thread ) void _Scheduler_simple_smp_Schedule( Thread_Control *thread ) { - ( void ) thread; + if ( thread->is_in_the_air ) { + Scheduler_SMP_Control *self = _Scheduler_SMP_Instance(); + + thread->is_in_the_air = false; + + _Scheduler_simple_smp_Schedule_highest_ready( self, thread ); + } } -- cgit v1.2.3