From e5ca54c99682a264568d95d8a5db555ea8357e9c Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 7 Aug 2013 21:19:55 +0200 Subject: score: PR2136: Fix _Thread_Change_priority() Add call to _Scheduler_Schedule() in missing path after _Thread_Set_transient() in _Thread_Change_priority(). See also sptests/spintrcritical19. Add thread parameter to _Scheduler_Schedule(). This parameter is currently unused but may be used in future SMP schedulers. Do heir selection in _Scheduler_Schedule(). Use _Scheduler_Update_heir() for this in the particular scheduler implementation. Add and use _Scheduler_Generic_block(). --- cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/scheduler.h | 2 +- cpukit/score/include/rtems/score/scheduleredf.h | 2 +- .../score/include/rtems/score/scheduleredfimpl.h | 56 ++++++++++++++++++++++ cpukit/score/include/rtems/score/schedulerimpl.h | 35 +++++++++++++- .../score/include/rtems/score/schedulerpriority.h | 2 +- .../include/rtems/score/schedulerpriorityimpl.h | 12 ++++- cpukit/score/include/rtems/score/schedulersimple.h | 2 +- .../include/rtems/score/schedulersimpleimpl.h | 16 ++++++- .../score/include/rtems/score/schedulersimplesmp.h | 2 +- cpukit/score/include/rtems/score/threadimpl.h | 10 ---- cpukit/score/preinstall.am | 4 ++ cpukit/score/src/scheduleredfblock.c | 17 +++---- cpukit/score/src/scheduleredfschedule.c | 12 ++--- cpukit/score/src/scheduleredfyield.c | 9 +--- cpukit/score/src/schedulerpriorityblock.c | 16 ++----- cpukit/score/src/schedulerpriorityschedule.c | 4 +- cpukit/score/src/schedulersimpleblock.c | 15 +++--- cpukit/score/src/schedulersimpleschedule.c | 9 ++-- cpukit/score/src/schedulersimplesmp.c | 4 +- cpukit/score/src/schedulersimpleyield.c | 5 +- cpukit/score/src/threadchangepriority.c | 14 ++++-- 22 files changed, 164 insertions(+), 85 deletions(-) create mode 100644 cpukit/score/include/rtems/score/scheduleredfimpl.h diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 7cde82cf92..a725ffcba1 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -50,6 +50,7 @@ include_rtems_score_HEADERS += include/rtems/score/scheduler.h include_rtems_score_HEADERS += include/rtems/score/schedulerimpl.h include_rtems_score_HEADERS += include/rtems/score/schedulercbs.h include_rtems_score_HEADERS += include/rtems/score/scheduleredf.h +include_rtems_score_HEADERS += include/rtems/score/scheduleredfimpl.h include_rtems_score_HEADERS += include/rtems/score/schedulerpriority.h include_rtems_score_HEADERS += include/rtems/score/schedulerpriorityimpl.h include_rtems_score_HEADERS += include/rtems/score/schedulersimple.h diff --git a/cpukit/score/include/rtems/score/scheduler.h b/cpukit/score/include/rtems/score/scheduler.h index a34387d8c7..10a2a974af 100644 --- a/cpukit/score/include/rtems/score/scheduler.h +++ b/cpukit/score/include/rtems/score/scheduler.h @@ -46,7 +46,7 @@ typedef struct { void ( *initialize )(void); /** Implements the scheduling decision logic (policy). */ - void ( *schedule )(void); + void ( *schedule )( Thread_Control *thread ); /** * @brief Voluntarily yields the processor per the scheduling policy. diff --git a/cpukit/score/include/rtems/score/scheduleredf.h b/cpukit/score/include/rtems/score/scheduleredf.h index b28bed1363..01f91e6c26 100644 --- a/cpukit/score/include/rtems/score/scheduleredf.h +++ b/cpukit/score/include/rtems/score/scheduleredf.h @@ -129,7 +129,7 @@ void _Scheduler_EDF_Block( * This kernel routine sets the heir thread to be the next ready thread * in the rbtree ready queue. */ -void _Scheduler_EDF_Schedule( void ); +void _Scheduler_EDF_Schedule( Thread_Control *thread ); /** * @brief Allocates EDF specific information of @a the_thread. diff --git a/cpukit/score/include/rtems/score/scheduleredfimpl.h b/cpukit/score/include/rtems/score/scheduleredfimpl.h new file mode 100644 index 0000000000..04201bcdfc --- /dev/null +++ b/cpukit/score/include/rtems/score/scheduleredfimpl.h @@ -0,0 +1,56 @@ +/** + * @file + * + * @ingroup ScoreSchedulerEDF + * + * @brief EDF Scheduler Implementation + */ + +/* + * Copryight (c) 2011 Petr Benes. + * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_SCHEDULEREDFIMPL_H +#define _RTEMS_SCORE_SCHEDULEREDFIMPL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup ScoreSchedulerEDF EDF + * + * @{ + */ + +RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Schedule_body( + Thread_Control *thread, + bool force_dispatch +) +{ + RBTree_Node *first = _RBTree_First(&_Scheduler_EDF_Ready_queue, RBT_LEFT); + Scheduler_EDF_Per_thread *sched_info = + _RBTree_Container_of(first, Scheduler_EDF_Per_thread, Node); + Thread_Control *heir = (Thread_Control *) sched_info->thread; + + ( void ) thread; + + _Scheduler_Update_heir( heir, force_dispatch ); +} + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif +/* end of include file */ diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h index 5ea4bb8b74..2d9957a62a 100644 --- a/cpukit/score/include/rtems/score/schedulerimpl.h +++ b/cpukit/score/include/rtems/score/schedulerimpl.h @@ -20,6 +20,7 @@ #define _RTEMS_SCORE_SCHEDULERIMPL_H #include +#include #ifdef __cplusplus extern "C" { @@ -59,10 +60,12 @@ void _Scheduler_Handler_initialization( void ); * * This kernel routine implements the scheduling decision logic for * the scheduler. It does NOT dispatch. + * + * @param[in] thread The thread which state changed previously. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( void ) +RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( Thread_Control *thread ) { - _Scheduler.Operations.schedule(); + _Scheduler.Operations.schedule( thread ); } /** @@ -237,6 +240,34 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle( ( *_Scheduler.Operations.start_idle )( thread, processor ); } +RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir( + Thread_Control *heir, + bool force_dispatch +) +{ + Thread_Control *executing = _Thread_Executing; + + _Thread_Heir = heir; + + if ( executing != heir && ( force_dispatch || executing->is_preemptible ) ) + _Thread_Dispatch_necessary = true; +} + +RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block( + void ( *extract )( Thread_Control *thread ), + void ( *schedule )( Thread_Control *thread, bool force_dispatch ), + Thread_Control *thread +) +{ + ( *extract )( thread ); + + /* TODO: flash critical section? */ + + if ( _Thread_Is_executing( thread ) || _Thread_Is_heir( thread ) ) { + ( *schedule )( thread, true ); + } +} + /** * Macro testing whether @a p1 has lower priority than @a p2 * in the intuitive sense of priority. diff --git a/cpukit/score/include/rtems/score/schedulerpriority.h b/cpukit/score/include/rtems/score/schedulerpriority.h index 69649435bd..cbe0066d8d 100644 --- a/cpukit/score/include/rtems/score/schedulerpriority.h +++ b/cpukit/score/include/rtems/score/schedulerpriority.h @@ -93,7 +93,7 @@ void _Scheduler_priority_Block( * This kernel routine sets the heir thread to be the next ready thread * by invoking the_scheduler->ready_queue->operations->first(). */ -void _Scheduler_priority_Schedule(void); +void _Scheduler_priority_Schedule( Thread_Control *thread ); /** * @brief Allocates @a the_thread->scheduler. diff --git a/cpukit/score/include/rtems/score/schedulerpriorityimpl.h b/cpukit/score/include/rtems/score/schedulerpriorityimpl.h index 8a8917ca1b..73c635dced 100644 --- a/cpukit/score/include/rtems/score/schedulerpriorityimpl.h +++ b/cpukit/score/include/rtems/score/schedulerpriorityimpl.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -182,11 +183,18 @@ RTEMS_INLINE_ROUTINE void _Scheduler_priority_Ready_queue_requeue( * This kernel routine implements scheduling decision logic * for priority-based scheduling. */ -RTEMS_INLINE_ROUTINE void _Scheduler_priority_Schedule_body(void) +RTEMS_INLINE_ROUTINE void _Scheduler_priority_Schedule_body( + Thread_Control *thread, + bool force_dispatch +) { - _Thread_Heir = _Scheduler_priority_Ready_queue_first( + Thread_Control *heir = _Scheduler_priority_Ready_queue_first( (Chain_Control *) _Scheduler.information ); + + ( void ) thread; + + _Scheduler_Update_heir( heir, force_dispatch ); } /** diff --git a/cpukit/score/include/rtems/score/schedulersimple.h b/cpukit/score/include/rtems/score/schedulersimple.h index 5180d36087..477ea2c026 100644 --- a/cpukit/score/include/rtems/score/schedulersimple.h +++ b/cpukit/score/include/rtems/score/schedulersimple.h @@ -66,7 +66,7 @@ void _Scheduler_simple_Initialize( void ); * on the ready queue by getting the first node in the scheduler * information. */ -void _Scheduler_simple_Schedule( void ); +void _Scheduler_simple_Schedule( Thread_Control *thread ); /** * @brief Invoked when a thread wishes to voluntarily diff --git a/cpukit/score/include/rtems/score/schedulersimpleimpl.h b/cpukit/score/include/rtems/score/schedulersimpleimpl.h index 076d1a9258..51d37741b1 100644 --- a/cpukit/score/include/rtems/score/schedulersimpleimpl.h +++ b/cpukit/score/include/rtems/score/schedulersimpleimpl.h @@ -21,7 +21,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -96,6 +96,20 @@ RTEMS_INLINE_ROUTINE void _Scheduler_simple_Insert_priority_fifo( ); } +RTEMS_INLINE_ROUTINE void _Scheduler_simple_Schedule_body( + Thread_Control *thread, + bool force_dispatch +) +{ + Thread_Control *heir = (Thread_Control *) _Chain_First( + (Chain_Control *) _Scheduler.information + ); + + ( void ) thread; + + _Scheduler_Update_heir( heir, force_dispatch ); +} + /** @} */ #ifdef __cplusplus diff --git a/cpukit/score/include/rtems/score/schedulersimplesmp.h b/cpukit/score/include/rtems/score/schedulersimplesmp.h index 1b827cbabe..6cc87f3dec 100644 --- a/cpukit/score/include/rtems/score/schedulersimplesmp.h +++ b/cpukit/score/include/rtems/score/schedulersimplesmp.h @@ -85,7 +85,7 @@ void _Scheduler_simple_smp_Extract( Thread_Control *thread ); void _Scheduler_simple_smp_Yield( Thread_Control *thread ); -void _Scheduler_simple_smp_Schedule( void ); +void _Scheduler_simple_smp_Schedule( Thread_Control *thread ); void _Scheduler_simple_smp_Start_idle( Thread_Control *thread, diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 717f00b4e8..e07b39266d 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -497,16 +497,6 @@ RTEMS_INLINE_ROUTINE bool _Thread_Is_heir ( return ( the_thread == _Thread_Heir ); } -/** - * This function returns true if the currently executing thread - * is also the heir thread, and false otherwise. - */ - -RTEMS_INLINE_ROUTINE bool _Thread_Is_executing_also_the_heir( void ) -{ - return ( _Thread_Executing == _Thread_Heir ); -} - /** * This routine clears any blocking state for the_thread. It performs * any necessary scheduling operations including the selection of diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 80fad5b97e..14d873ce4c 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -183,6 +183,10 @@ $(PROJECT_INCLUDE)/rtems/score/scheduleredf.h: include/rtems/score/scheduleredf. $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/scheduleredf.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/scheduleredf.h +$(PROJECT_INCLUDE)/rtems/score/scheduleredfimpl.h: include/rtems/score/scheduleredfimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/scheduleredfimpl.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/scheduleredfimpl.h + $(PROJECT_INCLUDE)/rtems/score/schedulerpriority.h: include/rtems/score/schedulerpriority.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/schedulerpriority.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/schedulerpriority.h diff --git a/cpukit/score/src/scheduleredfblock.c b/cpukit/score/src/scheduleredfblock.c index 4ad767d7bf..80bb1d5549 100644 --- a/cpukit/score/src/scheduleredfblock.c +++ b/cpukit/score/src/scheduleredfblock.c @@ -19,20 +19,15 @@ #include "config.h" #endif -#include -#include +#include void _Scheduler_EDF_Block( Thread_Control *the_thread ) { - _Scheduler_EDF_Extract( the_thread ); - - /* TODO: flash critical section? */ - - if ( _Thread_Is_heir( the_thread ) ) - _Scheduler_EDF_Schedule(); - - if ( _Thread_Is_executing( the_thread ) ) - _Thread_Dispatch_necessary = true; + _Scheduler_Generic_block( + _Scheduler_EDF_Extract, + _Scheduler_EDF_Schedule_body, + the_thread + ); } diff --git a/cpukit/score/src/scheduleredfschedule.c b/cpukit/score/src/scheduleredfschedule.c index dbe21dc491..a71a5b52ba 100644 --- a/cpukit/score/src/scheduleredfschedule.c +++ b/cpukit/score/src/scheduleredfschedule.c @@ -18,15 +18,9 @@ #include "config.h" #endif -#include -#include -#include +#include -void _Scheduler_EDF_Schedule(void) +void _Scheduler_EDF_Schedule( Thread_Control *thread ) { - RBTree_Node *first = _RBTree_First(&_Scheduler_EDF_Ready_queue, RBT_LEFT); - Scheduler_EDF_Per_thread *sched_info = - _RBTree_Container_of(first, Scheduler_EDF_Per_thread, Node); - - _Thread_Heir = (Thread_Control *) sched_info->thread; + _Scheduler_EDF_Schedule_body( thread, false ); } diff --git a/cpukit/score/src/scheduleredfyield.c b/cpukit/score/src/scheduleredfyield.c index 4ba9f79b77..fc5b13a7a0 100644 --- a/cpukit/score/src/scheduleredfyield.c +++ b/cpukit/score/src/scheduleredfyield.c @@ -19,11 +19,7 @@ #include "config.h" #endif -#include -#include -#include -#include -#include +#include void _Scheduler_EDF_Yield( Thread_Control *thread ) { @@ -44,8 +40,7 @@ void _Scheduler_EDF_Yield( Thread_Control *thread ) _ISR_Flash( level ); - _Scheduler_EDF_Schedule(); - _Thread_Dispatch_necessary = true; + _Scheduler_EDF_Schedule_body( thread, false ); _ISR_Enable( level ); } diff --git a/cpukit/score/src/schedulerpriorityblock.c b/cpukit/score/src/schedulerpriorityblock.c index 9e48101f9e..329ddd7bda 100644 --- a/cpukit/score/src/schedulerpriorityblock.c +++ b/cpukit/score/src/schedulerpriorityblock.c @@ -21,20 +21,14 @@ #endif #include -#include void _Scheduler_priority_Block( Thread_Control *the_thread ) { - _Scheduler_priority_Ready_queue_extract( the_thread ); - - /* TODO: flash critical section? */ - - if ( _Thread_Is_heir( the_thread ) ) - _Scheduler_priority_Schedule_body(); - - if ( _Thread_Is_executing( the_thread ) ) - _Thread_Dispatch_necessary = true; - + _Scheduler_Generic_block( + _Scheduler_priority_Ready_queue_extract, + _Scheduler_priority_Schedule_body, + the_thread + ); } diff --git a/cpukit/score/src/schedulerpriorityschedule.c b/cpukit/score/src/schedulerpriorityschedule.c index 22ed5f403c..42647e617b 100644 --- a/cpukit/score/src/schedulerpriorityschedule.c +++ b/cpukit/score/src/schedulerpriorityschedule.c @@ -20,7 +20,7 @@ #include -void _Scheduler_priority_Schedule(void) +void _Scheduler_priority_Schedule( Thread_Control *thread ) { - _Scheduler_priority_Schedule_body(); + _Scheduler_priority_Schedule_body( thread, false ); } diff --git a/cpukit/score/src/schedulersimpleblock.c b/cpukit/score/src/schedulersimpleblock.c index b9753b5954..1e6e8a0b47 100644 --- a/cpukit/score/src/schedulersimpleblock.c +++ b/cpukit/score/src/schedulersimpleblock.c @@ -19,18 +19,15 @@ #include "config.h" #endif -#include -#include +#include void _Scheduler_simple_Block( Thread_Control *the_thread ) { - _Scheduler_simple_Extract(the_thread); - - if ( _Thread_Is_heir( the_thread ) ) - _Scheduler_simple_Schedule(); - - if ( _Thread_Is_executing( the_thread ) ) - _Thread_Dispatch_necessary = true; + _Scheduler_Generic_block( + _Scheduler_simple_Extract, + _Scheduler_simple_Schedule_body, + the_thread + ); } diff --git a/cpukit/score/src/schedulersimpleschedule.c b/cpukit/score/src/schedulersimpleschedule.c index b60f096b09..5018e0b638 100644 --- a/cpukit/score/src/schedulersimpleschedule.c +++ b/cpukit/score/src/schedulersimpleschedule.c @@ -18,12 +18,9 @@ #include "config.h" #endif -#include -#include +#include -void _Scheduler_simple_Schedule(void) +void _Scheduler_simple_Schedule( Thread_Control *thread ) { - _Thread_Heir = (Thread_Control *) _Chain_First( - (Chain_Control *) _Scheduler.information - ); + _Scheduler_simple_Schedule_body( thread, false ); } diff --git a/cpukit/score/src/schedulersimplesmp.c b/cpukit/score/src/schedulersimplesmp.c index db08b96ab3..e26151025c 100644 --- a/cpukit/score/src/schedulersimplesmp.c +++ b/cpukit/score/src/schedulersimplesmp.c @@ -182,9 +182,9 @@ void _Scheduler_simple_smp_Yield( Thread_Control *thread ) _ISR_Enable( level ); } -void _Scheduler_simple_smp_Schedule( void ) +void _Scheduler_simple_smp_Schedule( Thread_Control *thread ) { - /* Nothing to do */ + ( void ) thread; } void _Scheduler_simple_smp_Start_idle( diff --git a/cpukit/score/src/schedulersimpleyield.c b/cpukit/score/src/schedulersimpleyield.c index cb8dc6fc92..43784d65f9 100644 --- a/cpukit/score/src/schedulersimpleyield.c +++ b/cpukit/score/src/schedulersimpleyield.c @@ -32,10 +32,7 @@ void _Scheduler_simple_Yield( Thread_Control *thread ) _ISR_Flash( level ); - _Scheduler_simple_Schedule(); - - if ( !_Thread_Is_heir( thread ) ) - _Thread_Dispatch_necessary = true; + _Scheduler_simple_Schedule_body( thread, false ); _ISR_Enable( level ); } diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c index b4437313a7..b3d79844c2 100644 --- a/cpukit/score/src/threadchangepriority.c +++ b/cpukit/score/src/threadchangepriority.c @@ -62,6 +62,15 @@ void _Thread_Change_priority( /* Only clear the transient state if it wasn't set already */ if ( ! _States_Is_transient( original_state ) ) the_thread->current_state = _States_Clear( STATES_TRANSIENT, state ); + + /* + * The thread may have new blocking states added by interrupt service + * routines after the change into the transient state. This will not + * result in a _Scheduler_Block() operation. Make sure we select an heir + * now. + */ + _Scheduler_Schedule( the_thread ); + _ISR_Enable( level ); if ( _States_Is_waiting_on_thread_queue( state ) ) { _Thread_queue_Requeue( the_thread->Wait.queue, the_thread ); @@ -91,10 +100,7 @@ void _Thread_Change_priority( * We altered the set of thread priorities. So let's figure out * who is the heir and if we need to switch to them. */ - _Scheduler_Schedule(); + _Scheduler_Schedule( the_thread ); - if ( !_Thread_Is_executing_also_the_heir() && - _Thread_Executing->is_preemptible ) - _Thread_Dispatch_necessary = true; _ISR_Enable( level ); } -- cgit v1.2.3