From ac532f33508cc052108a8f8d9ab1eb933bb5a6f8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 4 Jul 2014 13:40:10 +0200 Subject: score: Add _Scheduler_Help() Manage the help state of threads with respect to scheduling decisions. --- cpukit/score/include/rtems/score/mrspimpl.h | 32 +++++--- cpukit/score/include/rtems/score/scheduler.h | 96 ++++++++++++++++++++++ cpukit/score/include/rtems/score/schedulerimpl.h | 41 +++++++++ .../score/include/rtems/score/schedulersmpimpl.h | 4 +- 4 files changed, 159 insertions(+), 14 deletions(-) diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h index 5efb619d0b..6aa45a8c4f 100644 --- a/cpukit/score/include/rtems/score/mrspimpl.h +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -102,6 +102,7 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership( _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node ); mrsp->initial_priority_of_owner = initial_priority; _MRSP_Elevate_priority( mrsp, new_owner, ceiling_priority ); + _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER ); } RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize( @@ -185,6 +186,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( MRSP_Rival rival; bool previous_life_protection; unsigned int state; + Scheduler_Help_state previous_help_state; _MRSP_Elevate_priority( mrsp, executing, ceiling_priority ); @@ -193,6 +195,8 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node ); _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node ); _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource ); + previous_help_state = + _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL ); _MRSP_Set_root( &executing->Resource_node, _Resource_Node_get_root( owner ) @@ -234,11 +238,10 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( mrsp->initial_priority_of_owner = initial_priority; status = MRSP_SUCCESSFUL; } else { - Resource_Node *executing_node = &executing->Resource_node; - - _Resource_Node_extract( executing_node ); - _Resource_Node_set_dependency( executing_node, NULL ); - _MRSP_Set_root( executing_node, executing_node ); + _Resource_Node_extract( &executing->Resource_node ); + _Resource_Node_set_dependency( &executing->Resource_node, NULL ); + _Scheduler_Thread_change_help_state( executing, previous_help_state ); + _MRSP_Set_root( &executing->Resource_node, &executing->Resource_node ); _MRSP_Restore_priority( mrsp, executing, initial_priority ); status = MRSP_TIMEOUT; @@ -324,16 +327,21 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( _Resource_Set_owner( &mrsp->Resource, NULL ); } else { MRSP_Rival *rival = (MRSP_Rival *) _Chain_First( &mrsp->Rivals ); - Resource_Node *new_owner = &rival->thread->Resource_node; - - _Resource_Node_extract( new_owner ); - _Resource_Node_set_dependency( new_owner, NULL ); - _Resource_Node_add_resource( new_owner, &mrsp->Resource ); - _Resource_Set_owner( &mrsp->Resource, new_owner ); - _MRSP_Set_root( new_owner, new_owner ); + Thread_Control *new_owner = rival->thread; + + _Resource_Node_extract( &new_owner->Resource_node ); + _Resource_Node_set_dependency( &new_owner->Resource_node, NULL ); + _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource ); + _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node ); + _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER ); + _MRSP_Set_root( &new_owner->Resource_node, &new_owner->Resource_node ); _MRSP_Add_state( rival, MRSP_RIVAL_STATE_NEW_OWNER ); } + if ( !_Resource_Node_owns_resources( &executing->Resource_node ) ) { + _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF ); + } + return MRSP_SUCCESSFUL; } diff --git a/cpukit/score/include/rtems/score/scheduler.h b/cpukit/score/include/rtems/score/scheduler.h index 831accb7ae..bb30a8e61e 100644 --- a/cpukit/score/include/rtems/score/scheduler.h +++ b/cpukit/score/include/rtems/score/scheduler.h @@ -161,6 +161,75 @@ struct Scheduler_Control { uint32_t name; }; +#if defined(RTEMS_SMP) +/** + * @brief State to indicate potential help for other threads. + * + * @dot + * digraph state { + * y [label="HELP YOURSELF"]; + * ao [label="HELP ACTIVE OWNER"]; + * ar [label="HELP ACTIVE RIVAL"]; + * + * y -> ao [label="obtain"]; + * y -> ar [label="wait for obtain"]; + * ao -> y [label="last release"]; + * ao -> r [label="wait for obtain"]; + * ar -> r [label="timeout"]; + * ar -> ao [label="timeout"]; + * } + * @enddot + */ +typedef enum { + /** + * @brief This scheduler node is solely used by the owner thread. + * + * This thread owns no resources using a helping protocol and thus does not + * take part in the scheduler helping protocol. No help will be provided for + * other thread. + */ + SCHEDULER_HELP_YOURSELF, + + /** + * @brief This scheduler node is owned by a thread actively owning a resource. + * + * This scheduler node can be used to help out threads. + * + * In case this scheduler node changes its state from ready to scheduled and + * the thread executes using another node, then an idle thread will be + * provided as a user of this node to temporarily execute on behalf of the + * owner thread. Thus lower priority threads are denied access to the + * processors of this scheduler instance. + * + * In case a thread actively owning a resource performs a blocking operation, + * then an idle thread will be used also in case this node is in the + * scheduled state. + */ + SCHEDULER_HELP_ACTIVE_OWNER, + + /** + * @brief This scheduler node is owned by a thread actively obtaining a + * resource currently owned by another thread. + * + * This scheduler node can be used to help out threads. + * + * The thread owning this node is ready and will give away its processor in + * case the thread owning the resource asks for help. + */ + SCHEDULER_HELP_ACTIVE_RIVAL, + + /** + * @brief This scheduler node is owned by a thread obtaining a + * resource currently owned by another thread. + * + * This scheduler node can be used to help out threads. + * + * The thread owning this node is blocked. + */ + SCHEDULER_HELP_PASSIVE +} Scheduler_Help_state; +#endif + /** * @brief Scheduler node for per-thread data. */ @@ -178,10 +247,37 @@ struct Scheduler_Node { */ Chain_Node Node; + /** + * @brief The thread using this node. + */ + Thread_Control *user; + + /** + * @brief The help state of this node. + */ + Scheduler_Help_state help_state; + /** * @brief The thread owning this node. */ Thread_Control *owner; + + /** + * @brief The idle thread claimed by this node in case the help state is + * SCHEDULER_HELP_ACTIVE_OWNER. + * + * Active owners will lend their own node to an idle thread in case they + * execute currently using another node or in case they perform a blocking + * operation. This is necessary to ensure the priority ceiling protocols + * work across scheduler boundaries. + */ + Thread_Control *idle; + + /** + * @brief The thread accepting help by this node in case the help state is + * not SCHEDULER_HELP_YOURSELF. + */ + Thread_Control *accepts_help; #endif }; diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h index 1a8b6b0f1d..edb68b649a 100644 --- a/cpukit/score/include/rtems/score/schedulerimpl.h +++ b/cpukit/score/include/rtems/score/schedulerimpl.h @@ -77,6 +77,15 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU( return _Scheduler_Get_by_CPU_index( cpu_index ); } +#if defined(RTEMS_SMP) +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_user( + const Scheduler_Node *node +) +{ + return node->user; +} +#endif + /** * The preferred method to add a new scheduler is to define the jump table * entries and add a case to the _Scheduler_Initialize routine. @@ -658,7 +667,11 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize( ) { #if defined(RTEMS_SMP) + node->user = the_thread; + node->help_state = SCHEDULER_HELP_YOURSELF; node->owner = the_thread; + node->idle = NULL; + node->accepts_help = the_thread; #else (void) node; (void) the_thread; @@ -672,6 +685,34 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_owner( { return node->owner; } + +RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_idle( + const Scheduler_Node *node +) +{ + return node->idle; +} + +/** + * @brief Changes the scheduler help state of a thread. + * + * @param[in] the_thread The thread. + * @param[in] new_help_state The new help state. + * + * @return The previous help state. + */ +RTEMS_INLINE_ROUTINE Scheduler_Help_state _Scheduler_Thread_change_help_state( + Thread_Control *the_thread, + Scheduler_Help_state new_help_state +) +{ + Scheduler_Node *node = _Scheduler_Thread_get_node( the_thread ); + Scheduler_Help_state previous_help_state = node->help_state; + + node->help_state = new_help_state; + + return previous_help_state; +} #endif /** @} */ diff --git a/cpukit/score/include/rtems/score/schedulersmpimpl.h b/cpukit/score/include/rtems/score/schedulersmpimpl.h index 3ec499b99f..b7d86a36e8 100644 --- a/cpukit/score/include/rtems/score/schedulersmpimpl.h +++ b/cpukit/score/include/rtems/score/schedulersmpimpl.h @@ -455,8 +455,8 @@ static inline void _Scheduler_SMP_Allocate_processor( Scheduler_SMP_Allocate_processor allocate_processor ) { - Thread_Control *scheduled_thread = _Scheduler_Node_get_owner( scheduled ); - Thread_Control *victim_thread = _Scheduler_Node_get_owner( victim ); + Thread_Control *scheduled_thread = _Scheduler_Node_get_user( scheduled ); + Thread_Control *victim_thread = _Scheduler_Node_get_user( victim ); _Scheduler_SMP_Node_change_state( _Scheduler_SMP_Node_downcast( scheduled ), -- cgit v1.2.3